<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Java并发体系-第三阶段-JUC并发包-[2] | 风祈的时光录</title><meta name="keywords" content="Java并发，原理，源码"><meta name="author" content="youthlql"><meta name="copyright" content="youthlql"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="万字系列长文讲解-Java并发体系-第三阶段-JUC并发包。JUC在高并发编程中使用频率非常高，这里会详细介绍其用法。">
<meta property="og:type" content="article">
<meta property="og:title" content="Java并发体系-第三阶段-JUC并发包-[2]">
<meta property="og:url" content="https://imlql.cn/post/70c90e5d.html">
<meta property="og:site_name" content="风祈的时光录">
<meta property="og:description" content="万字系列长文讲解-Java并发体系-第三阶段-JUC并发包。JUC在高并发编程中使用频率非常高，这里会详细介绍其用法。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png">
<meta property="article:published_time" content="2020-10-10T14:13:58.000Z">
<meta property="article:modified_time" content="2022-07-24T11:02:09.800Z">
<meta property="article:author" content="youthlql">
<meta property="article:tag" content="Java并发">
<meta property="article:tag" content="原理">
<meta property="article:tag" content="源码">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png"><link rel="shortcut icon" href="https://npm.elemecdn.com/youthlql@1.0.8/blog/favicon.png"><link rel="canonical" href="https://imlql.cn/post/70c90e5d"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://npm.elemecdn.com/@fortawesome/fontawesome-free@6/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/@fancyapps/ui/dist/fancybox.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?f693ff99cc7e613b88cf5b729a14b48b";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery@2/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Java并发体系-第三阶段-JUC并发包-[2]',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-07-24 19:02:09'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><link rel="stylesheet" href="https://npm.elemecdn.com/lql_static@latest/butterfly_static/css/ali_icon.css"><link rel="stylesheet" href="https://npm.elemecdn.com/lql_static@latest/butterfly_static/css/2-24-mogai.css"><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="风祈的时光录" type="application/atom+xml">
</head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/avatar/2.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data is-center"><div class="data-item"><a href="/archives/"><div class="headline">文章</div><div class="length-num">37</div></a></div><div class="data-item"><a href="/tags/"><div class="headline">标签</div><div class="length-num">21</div></a></div><div class="data-item"><a href="/categories/"><div class="headline">分类</div><div class="length-num">13</div></a></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw iconfont icon-shouyex"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw iconfont icon-zuixinwenzhang_huaban"></i><span> 找文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw iconfont icon-fenlei1"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw iconfont icon-biaoqian1"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw iconfont icon-shijianzhou"></i><span> 归档</span></a></li></ul></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">风祈的时光录</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw iconfont icon-shouyex"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw iconfont icon-zuixinwenzhang_huaban"></i><span> 找文章</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/categories/"><i class="fa-fw iconfont icon-fenlei1"></i><span> 分类</span></a></li><li><a class="site-page child" href="/tags/"><i class="fa-fw iconfont icon-biaoqian1"></i><span> 标签</span></a></li><li><a class="site-page child" href="/archives/"><i class="fa-fw iconfont icon-shijianzhou"></i><span> 归档</span></a></li></ul></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Java并发体系-第三阶段-JUC并发包-[2]</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2020-10-10T14:13:58.000Z" title="发表于 2020-10-10 22:13:58">2020-10-10</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-24T11:02:09.800Z" title="更新于 2022-07-24 19:02:09">2022-07-24</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java%E5%B9%B6%E5%8F%91/">Java并发</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java%E5%B9%B6%E5%8F%91/%E5%8E%9F%E7%90%86/">原理</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">14k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>60分钟</span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="Phaser工具"><a href="#Phaser工具" class="headerlink" title="Phaser工具"></a>Phaser工具</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>java7中引入了一种新的可重复使用的同步屏障,称为移相器Phaser。Phaser拥有与<code>CyclicBarrier</code>和<code>CountDownLatch</code>类似的功能.</p>
<p>但是这个类提供了更加灵活的应用。CountDownLatch和CyclicBarrier都是只适用于固定数量的参与者。移相器适用于可变数目的屏障，在这个意义上，可以在任何时间注册新的参与者。并且在抵达屏障是可以注销已经注册的参与者。因此,注册到同步移相器的参与者的数目可能会随着时间的推移而变化。</p>
<p>如CyclicBarrier一样,移相器可以重复使用,这意味着当前参与者到达移相器后,可以再一次注册自己并等待另一次到达.</p>
<p>移相器的另一个重要特征是:移相器可能是分层的,这允许你以树形结构来安排移相器以减少竞争</p>
<p><strong>简单例子：</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/10/11 21:57</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhaserTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> Random RANDOM = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Phaser phaser = <span class="keyword">new</span> Phaser();</span><br><span class="line">        <span class="comment">//JDK8语法，相当于创建5个线程</span></span><br><span class="line">        IntStream.rangeClosed(<span class="number">1</span>,<span class="number">5</span>).boxed().map(i-&gt;phaser).forEach(Task::<span class="keyword">new</span>);</span><br><span class="line">		<span class="comment">//主线程也注册进去</span></span><br><span class="line">        phaser.register();</span><br><span class="line"></span><br><span class="line">        phaser.arriveAndAwaitAdvance();<span class="comment">//main线程   到达并等待前行</span></span><br><span class="line">        System.out.println(<span class="string">&quot;All of work are finished.&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Task</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Phaser phaser;</span><br><span class="line"></span><br><span class="line">        Task(Phaser phaser) &#123;</span><br><span class="line">            <span class="keyword">this</span>.phaser = phaser;</span><br><span class="line">            phaser.register();<span class="comment">//把自己加入计数器中</span></span><br><span class="line">            start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;The worker[ &quot;</span>+getName()+ <span class="string">&quot; ]&quot;</span> +<span class="string">&quot; is working.&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(RANDOM.nextInt(<span class="number">5</span>));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            phaser.arriveAndAwaitAdvance();<span class="comment">//自己完成，等待其他线程完成。  到达并等待前行</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>结果：</strong></p>
<pre><code>The worker[ Thread-1 ] is working.
The worker[ Thread-2 ] is working.
The worker[ Thread-0 ] is working.
The worker[ Thread-4 ] is working.
The worker[ Thread-3 ] is working.
All of work are finished.
</code></pre>
<h2 id="重复使用的例子"><a href="#重复使用的例子" class="headerlink" title="重复使用的例子"></a>重复使用的例子</h2><p>​    </p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">跑完步，需要去骑自行车，骑完自行车需要去跳高</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhaserTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> Random RANDOM = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Phaser phaser = <span class="keyword">new</span> Phaser(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Athletes(i,phaser).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Athletes</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> no;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Phaser phaser;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        Athletes(<span class="keyword">int</span> no, Phaser phaser) &#123;</span><br><span class="line">            <span class="keyword">this</span>.no = no;</span><br><span class="line">            <span class="keyword">this</span>.phaser = phaser;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                System.out.println(no + <span class="string">&quot; start running.&quot;</span>);</span><br><span class="line">                TimeUnit.MILLISECONDS.sleep(RANDOM.nextInt(<span class="number">100</span>));</span><br><span class="line">                System.out.println(no + <span class="string">&quot; end running.&quot;</span>);</span><br><span class="line">                phaser.arriveAndAwaitAdvance();</span><br><span class="line"></span><br><span class="line">                System.out.println(no + <span class="string">&quot; start bicycle.&quot;</span>);</span><br><span class="line">                TimeUnit.MILLISECONDS.sleep(RANDOM.nextInt(<span class="number">100</span>));</span><br><span class="line">                System.out.println(no + <span class="string">&quot; end bicycle.&quot;</span>);</span><br><span class="line">                phaser.arriveAndAwaitAdvance();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">                System.out.println(no + <span class="string">&quot; start long jump.&quot;</span>);</span><br><span class="line">                TimeUnit.MILLISECONDS.sleep(RANDOM.nextInt(<span class="number">100</span>));</span><br><span class="line">                System.out.println(no + <span class="string">&quot; end long jump.&quot;</span>);</span><br><span class="line">                phaser.arriveAndAwaitAdvance();</span><br><span class="line"></span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>


<p>​    </p>
<p><strong>结果</strong>：</p>
<pre><code>1 start running.
2 start running.
3 start running.
3 end running.
2 end running.
1 end running.
1 start bicycle.
2 start bicycle.
3 start bicycle.
3 end bicycle.
2 end bicycle.
1 end bicycle.
1 start long jump.
2 start long jump.
3 start long jump.
2 end long jump.
1 end long jump.
3 end long jump.
</code></pre>
<p>可以看到栅栏被重复利用了。</p>
<h2 id="动态减少"><a href="#动态减少" class="headerlink" title="动态减少"></a>动态减少</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.Random;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> Random RANDOM = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Phaser phaser = <span class="keyword">new</span> Phaser(<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> Athletes(i,phaser).start();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//假设3号运动员受伤了</span></span><br><span class="line">        <span class="keyword">new</span> InjuredAthletes(<span class="number">3</span>, phaser).start();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//运动员受伤了，需要减少</span></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">InjuredAthletes</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> no;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Phaser phaser;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        InjuredAthletes(<span class="keyword">int</span> no, Phaser phaser) &#123;</span><br><span class="line">            <span class="keyword">this</span>.no = no;</span><br><span class="line">            <span class="keyword">this</span>.phaser = phaser;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                sport(no, phaser, <span class="string">&quot; start running.&quot;</span>, <span class="string">&quot; end running.&quot;</span>);</span><br><span class="line">                sport(no, phaser, <span class="string">&quot; start bicycle.&quot;</span>, <span class="string">&quot; end bicycle.&quot;</span>);</span><br><span class="line">                System.out.println(no + <span class="string">&quot;号运动员受伤了&quot;</span>);</span><br><span class="line">                phaser.arriveAndDeregister();<span class="comment">//动态减少</span></span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Athletes</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> no;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Phaser phaser;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        Athletes(<span class="keyword">int</span> no, Phaser phaser) &#123;</span><br><span class="line">            <span class="keyword">this</span>.no = no;</span><br><span class="line">            <span class="keyword">this</span>.phaser = phaser;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                sport(no, phaser, <span class="string">&quot; start running.&quot;</span>, <span class="string">&quot; end running.&quot;</span>);</span><br><span class="line">                sport(no, phaser, <span class="string">&quot; start bicycle.&quot;</span>, <span class="string">&quot; end bicycle.&quot;</span>);</span><br><span class="line">                sport(no, phaser, <span class="string">&quot; start long jump.&quot;</span>, <span class="string">&quot; end long jump.&quot;</span>);</span><br><span class="line"></span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sport</span><span class="params">(<span class="keyword">int</span> no, Phaser phaser, String x, String y)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        System.out.println(no + x);</span><br><span class="line">        TimeUnit.MILLISECONDS.sleep(RANDOM.nextInt(<span class="number">100</span>));</span><br><span class="line">        System.out.println(no + y);</span><br><span class="line">        phaser.arriveAndAwaitAdvance();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<p>结果：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">2 start running.</span><br><span class="line">1 start running.</span><br><span class="line">3 start running.</span><br><span class="line">2 end running.</span><br><span class="line">1 end running.</span><br><span class="line">3 end running.</span><br><span class="line">3 start bicycle.</span><br><span class="line">1 start bicycle.</span><br><span class="line">2 start bicycle.</span><br><span class="line">2 end bicycle.</span><br><span class="line">3 end bicycle.</span><br><span class="line">1 end bicycle.</span><br><span class="line">1 start long jump.</span><br><span class="line">2 start long jump.</span><br><span class="line">3号运动员受伤了</span><br><span class="line">2 end long jump.</span><br><span class="line">1 end long jump.</span><br></pre></td></tr></table></figure>

<p>3号运动员受伤了，那么他就不能完成jump，3号运动员的<code>phaser.arriveAndAwaitAdvance()</code>也就无法执行，就会导致程序无法终止。因为Phaser数量是3个，只要三个线程都到了才会结束。所以说3号运动员受伤后，可以减少Phaser的数量：<code>phaser.arriveAndDeregister();//动态减少</code></p>
<p>​    </p>
<p>​    </p>
<p>​    </p>
<h2 id="常用API"><a href="#常用API" class="headerlink" title="常用API"></a>常用API</h2><h3 id="注册"><a href="#注册" class="headerlink" title="注册"></a>注册</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">register</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">bulkRegister</span><span class="params">(<span class="keyword">int</span> parties)</span></span></span><br></pre></td></tr></table></figure>


<p><strong>register</strong></p>
<ul>
<li>  是注册一个线程数，比较常用</li>
</ul>
<p><strong>bulkRegister</strong></p>
<ul>
<li>  可以批量注册</li>
</ul>
<h3 id="到达"><a href="#到达" class="headerlink" title="到达"></a>到达</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">arrive</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">arriveAndDeregister</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">arriveAndAwaitAdvance</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>

<p><strong>arrive</strong></p>
<ul>
<li>  这个到达后，不会阻塞，相当于<code>countdown</code>机制【因为countdown只会阻塞调用者，其它线程干完任务就可以干其他事】</li>
<li>  大家要理解一点，party 数和线程是没有关系的，不能说一个线程代表一个 party，因为我们完全可以在一个线程中重复调用 arrive() 方法。这么表达纯粹是方便理解用。</li>
</ul>
<p><strong>arriveAndAwaitAdvance</strong></p>
<ul>
<li>  到达后会阻塞，相当于<code>CyclicBarrier</code>机制</li>
</ul>
<p><strong>arriveAndDeregister</strong></p>
<ul>
<li>  当线程出现异常，不能正常到达时，可以调用该方法，<code>动态减少注册数</code></li>
</ul>
<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhaserTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Random RANDOM = <span class="keyword">new</span> Random();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Phaser phaser = <span class="keyword">new</span> Phaser(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">new</span> ArriveTask(i,phaser).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//等待全部任务进行完成</span></span><br><span class="line">        phaser.arriveAndAwaitAdvance();</span><br><span class="line">        System.out.println(<span class="string">&quot;The phase 1 work finish done.&quot;</span>);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ArriveTask</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Phaser phaser;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="title">ArriveTask</span><span class="params">(<span class="keyword">int</span> no,Phaser phaser)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(String.valueOf(no));</span><br><span class="line"></span><br><span class="line">            <span class="keyword">this</span>.phaser = phaser;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            System.out.println(getName() +  <span class="string">&quot; start working. &quot;</span>);</span><br><span class="line">            threadSleep();</span><br><span class="line">            System.out.println(getName() + <span class="string">&quot; The phase one is running.&quot;</span>);</span><br><span class="line">            phaser.arrive();</span><br><span class="line"></span><br><span class="line">            threadSleep();</span><br><span class="line">            System.out.println(getName() +  <span class="string">&quot; keep to other thing. &quot;</span>);</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">threadSleep</span><span class="params">()</span>  </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(RANDOM.nextInt(<span class="number">5</span>));</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="onAdvance"><a href="#onAdvance" class="headerlink" title="onAdvance()"></a>onAdvance()</h3><p>这个方法是 protected 的，所以它不是 phaser 提供的 API，从方法名字上也可以看出，它会在一个 phase 结束的时候被调用。</p>
<p>它的返回值代表是否应该终结（terminate）一个 phaser，之所以拿出来说，是因为我们经常会见到有人通过覆写该方法来自定义 phaser 的终结逻辑，如：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">onAdvance</span><span class="params">(<span class="keyword">int</span> phase, <span class="keyword">int</span> registeredParties)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> phase &gt;= N || registeredParties == <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>1、我们可以通过 <code>phaser.isTerminated()</code> 来检测一个 phaser 实例是否已经终结了</p>
<p>2、当一个 phaser 实例被终结以后，register()、arrive() 等这些方法都没有什么意义了，大家可以玩一玩，观察它们的返回值，原本应该返回 phase 值的，但是这个时候会返回一个负数。</p>
</blockquote>
<h3 id="监控子线程任务"><a href="#监控子线程任务" class="headerlink" title="监控子线程任务"></a>监控子线程任务</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">awaitAdvance</span><span class="params">(<span class="keyword">int</span> phase)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">awaitAdvanceInterruptibly</span><span class="params">(<span class="keyword">int</span> phase)</span> <span class="keyword">throws</span> InterruptedException</span></span><br></pre></td></tr></table></figure>


<ul>
<li>  相当于起到监控的作用</li>
<li>  如果子线程还没有执行完成，主线程就会阻塞</li>
<li>  相较而言，可以不用增加注册量</li>
</ul>
<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> Phaser phaser = <span class="keyword">new</span> Phaser(<span class="number">4</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">new</span> AwaitAdvance(i,phaser).start();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//等待全部任务进行完成</span></span><br><span class="line">    phaser.awaitAdvance(phaser.getPhase());</span><br><span class="line">    System.out.println(<span class="string">&quot;The phase 1 work finish done.&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h3 id="强制关闭"><a href="#强制关闭" class="headerlink" title="强制关闭"></a>强制关闭</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">forceTermination</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isTerminated</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>


<ul>
<li>  强制关闭phaser，但是<code>如果线程陷入阻塞，不会唤醒</code></li>
</ul>
<h2 id="监控API"><a href="#监控API" class="headerlink" title="监控API"></a>监控API</h2><h3 id="获取阶段数"><a href="#获取阶段数" class="headerlink" title="获取阶段数"></a>获取阶段数</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getPhase</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>


<ul>
<li>  返回当前相位数。 最大相位数为Integer.MAX_VALUE</li>
<li>  每增加一轮就会加一</li>
</ul>
<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PhaserTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Phaser phaser = <span class="keyword">new</span> Phaser(<span class="number">1</span>);</span><br><span class="line">        System.out.println(phaser.getPhase());</span><br><span class="line"></span><br><span class="line">        phaser.arriveAndAwaitAdvance();</span><br><span class="line">        System.out.println(phaser.getPhase());</span><br><span class="line"></span><br><span class="line">        phaser.arriveAndAwaitAdvance();</span><br><span class="line">        System.out.println(phaser.getPhase());</span><br><span class="line"></span><br><span class="line">        phaser.arriveAndAwaitAdvance();</span><br><span class="line">        System.out.println(phaser.getPhase());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong>：</p>
<pre><code>0
1
2
3
</code></pre>
<h3 id="获取注册的数"><a href="#获取注册的数" class="headerlink" title="获取注册的数"></a>获取注册的数</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getRegisteredParties</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>


<ul>
<li>  获得注册的线程数，相当于Countdown初始的的计数器</li>
<li>  可以动态更改</li>
</ul>
<h3 id="获得到达和未到达的数目"><a href="#获得到达和未到达的数目" class="headerlink" title="获得到达和未到达的数目"></a>获得到达和未到达的数目</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getArrivedParties</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getUnarrivedParties</span><span class="params">()</span></span></span><br></pre></td></tr></table></figure>


<p><strong>getArrivedParties</strong></p>
<ul>
<li>  获得已经到达的线程数，和没有到达的线程数</li>
</ul>
<p><strong>getUnarrivedParties</strong></p>
<ul>
<li>  获得没有到达的线程数，和没有到达的线程数</li>
</ul>
<h2 id="Phaser的分层结构"><a href="#Phaser的分层结构" class="headerlink" title="Phaser的分层结构"></a>Phaser的分层结构</h2><p>  <strong>Tiering</strong> 这个词本身就不好翻译，大家将就一下，要表达的意思就是，将多个 Phaser 实例构造成一棵树。</p>
<p>  1、第一个问题来了，为什么要把多个 Phaser 实例构造成一棵树，解决什么问题？有什么优点？</p>
<p>  Phaser 内部用一个 <code>state</code> 来管理状态变化，随着 parties 的增加，并发问题带来的性能影响会越来越严重。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 0-15: unarrived</span></span><br><span class="line"><span class="comment"> * 16-31: parties，   所以一个 phaser 实例最大支持 2^16-1=65535 个 parties</span></span><br><span class="line"><span class="comment"> * 32-62: phase，     31 位，那么最大值是 Integer.MAX_VALUE，达到最大值后又从 0 开始</span></span><br><span class="line"><span class="comment"> * 63: terminated</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">long</span> state;</span><br></pre></td></tr></table></figure>


<blockquote>
<p>通常我们在说 0-15 位这种，说的都是从低位开始的</p>
</blockquote>
<p>  state 的各种操作依赖于 CAS，典型的无锁操作，但是，在大量竞争的情况下，可能会造成很多的自旋。</p>
<p>  而构造一棵树就是为了降低每个节点（每个 Phaser 实例）的 parties 的数量，从而有效降低单个 state 值的竞争。</p>
<p>  2、第二个问题，它的结构是怎样的？</p>
<p>  这里我们不讲源码，用通俗一点的语言表述一下。我们先写段代码构造一棵树：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Phaser root = <span class="keyword">new</span> Phaser(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">Phaser n1 = <span class="keyword">new</span> Phaser(root, <span class="number">5</span>);</span><br><span class="line">Phaser n2 = <span class="keyword">new</span> Phaser(root, <span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">Phaser m1 = <span class="keyword">new</span> Phaser(n1, <span class="number">5</span>);</span><br><span class="line">Phaser m2 = <span class="keyword">new</span> Phaser(n1, <span class="number">5</span>);</span><br><span class="line">Phaser m3 = <span class="keyword">new</span> Phaser(n1, <span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">Phaser m4 = <span class="keyword">new</span> Phaser(n2, <span class="number">5</span>);</span><br></pre></td></tr></table></figure>


<p>  根据上面的代码，我们可以画出下面这个很简单的图：</p>
 <img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.8/Java_concurrency/Source_code/Third_stage/0002.png">

<p>  这棵树上有 7 个 phaser 实例，每个 phaser 实例在构造的时候，都指定了 parties 为 5，但是，对于每个拥有子节点的节点来说，每个子节点都是它的一个 party，我们可以通过 phaser.getRegisteredParties() 得到每个节点的 parties 数量：</p>
<ul>
<li>  m1、m2、m3、m4 的 parties 为 5</li>
<li>  n1 的 parties 为 5 + 3，n2 的 parties 为 5 + 1</li>
<li>  root 的 parties 为 5 + 2</li>
</ul>
<p>  结论应该非常容易理解，我们来阐述一下过程。</p>
<p>  在子节点注册第一个 party 的时候，这个时候会在父节点注册一个 party，注意这里说的是子节点添加第一个 party 的时候，而不是说实例构造的时候。</p>
<p>  在上面代码的基础上，大家可以试一下下面的这个代码：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Phaser m5 = <span class="keyword">new</span> Phaser(n2);</span><br><span class="line">System.out.println(<span class="string">&quot;n2 parties: &quot;</span> + n2.getRegisteredParties());</span><br><span class="line">m5.register();</span><br><span class="line">System.out.println(<span class="string">&quot;n2 parties: &quot;</span> + n2.getRegisteredParties());</span><br></pre></td></tr></table></figure>


<p>  第一行代码中构造了 m5 实例，但是此时它的 parties == 0，所以对于父节点 n2 来说，它的 parties 依然是 6，所以第二行代码输出 6。第三行代码注册了 m5 的第一个 party，显然，第四行代码会输出 7。</p>
<p>  当子节点的 parties 降为 0 的时候，会从父节点中”剥离”，我们在上面的基础上，再加两行代码：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">m5.arriveAndDeregister();</span><br><span class="line">System.out.println(<span class="string">&quot;n2 parties: &quot;</span> + n2.getRegisteredParties());</span><br></pre></td></tr></table></figure>


<p>  由于 m5 之前只有一个 parties，所以一次 arriveAndDeregister() 就会使得它的 parties 变为 0，此时第二行代码输出父节点 n2 的 parties 为 6。</p>
<blockquote>
<p>还有一点有趣的是，在非树的结构中，此时 m5 应该处于 terminated 状态，因为它的 parties 降为 0 了，不过在树的结构中，这个状态由 root 控制，所以我们依然可以执行 m5.register()…</p>
</blockquote>
<p>  3、每个 phaser 实例的 phase 周期有快有慢，怎么协调的？</p>
<p>  在组织成树的这种结构中，每个 phaser 实例的 phase 已经不受自己控制了，由 root 来统一协调，也就是说，root 当前的 phase 是多少，每个 phaser 的 phase 就是多少。</p>
<p>  那又有个问题，如果子节点的一个周期很快就结束了，要进入下一个周期怎么办？需要等！这个时候其实要等所有的节点都结束当前 phase，因为只有这样，root 节点才有可能结束当前 phase。</p>
<p>  我觉得 Phaser 中的树结构我们要这么理解，我们要把整棵树当做一个 phaser 实例，每个节点只是辅助用于降低并发而存在，整棵树还是需要满足 Phaser 语义的。</p>
<h1 id="阻塞队列"><a href="#阻塞队列" class="headerlink" title="阻塞队列"></a>阻塞队列</h1><h2 id="请谈谈对阻塞队列的理解"><a href="#请谈谈对阻塞队列的理解" class="headerlink" title="请谈谈对阻塞队列的理解"></a>请谈谈对阻塞队列的理解</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 阻塞队列</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 阻塞队列为空时，从队列中获取元素的操作将会被阻塞</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 阻塞队列为满时，往队列里添加元素的操作将会被阻塞</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> 阻塞队列的好处</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 多线程领域中，所谓阻塞，即某些情况下会挂起线程，一旦条件满足，线程唤醒。</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> 为什么需要 BlockingQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 我们不需要关心什么时候需要阻塞线程，什么时候需要唤醒线程了</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 在 JUC 包发布以前，多线程环境下，程序员需要自己控制这些细节，并且兼顾效率与线程安全</span></span><br></pre></td></tr></table></figure>

<h2 id="种类"><a href="#种类" class="headerlink" title="种类"></a>种类</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> ArrayBlockingQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 数组结构组成的有界阻塞队列</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> LinkedBlockingQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 由链表结构组成的有界(但大小默认值为 Integer.MAX_VALUE) 阻塞队列</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> PriorityBlockingQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 支持优先级排序的无界阻塞队列</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> DelayQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 使用优先级队列实现的延迟无界阻塞队列</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> SynchronousQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 不存储元素的阻塞队列，也即单个元素的队列</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> LinkedTransferQueue</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 由链表结构组成的无界阻塞队列</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> LinkedBlockingDeque</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> 由链表结构组成的双向阻塞队列</span></span><br></pre></td></tr></table></figure>

<h2 id="核心方法"><a href="#核心方法" class="headerlink" title="核心方法"></a>核心方法</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 抛出异常组</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> add(e)</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 队列满时 add 会抛出 java.lang.IllegalStateException: Queue full</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> remove()</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 队列空时 remove 会抛出 java.util.NoSuchElementException</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> element()</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 得到队首元素，队列为空时，抛出 java.util.NoSuchElementException</span></span><br><span class="line">		</span><br><span class="line"><span class="meta">#</span><span class="bash"> 返回布尔值组</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> offer(e)</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 往阻塞队列插入数据，成功时返回 <span class="literal">true</span>，失败时返回 <span class="literal">false</span></span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> poll()</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 从阻塞队列取出数据，成功时返回 数据，队列为空时返回 null</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> peek()</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 取出队首元素，成功时返回 数据，队列为空时返回 null</span></span><br><span class="line">		</span><br><span class="line"><span class="meta">#</span><span class="bash"> 阻塞</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> put(e)</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 往阻塞队列插入数据，无返回值，插入不成功时阻塞线程，直至插入成功 Or 线程中断</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> take()</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 从阻塞队列取出数据，成功返回数据，不成功时阻塞线程，直至取出成功 Or 线程中断</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 超时</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> offer(e,time,unit)</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 往阻塞队列插入数据，成功返回 <span class="literal">true</span>，不成功时线程阻塞等待超时时间，过时返回<span class="literal">false</span> 并放弃操作</span></span><br><span class="line"><span class="meta">	#</span><span class="bash"> poll(time,unit)</span></span><br><span class="line"><span class="meta">		#</span><span class="bash"> 从阻塞队列取出数据，成功返回 数据，队列为空时线程阻塞等待超时时间，过时返回<span class="literal">false</span> 并放弃操作</span></span><br></pre></td></tr></table></figure>

<h2 id="阻塞队列的使用场景"><a href="#阻塞队列的使用场景" class="headerlink" title="阻塞队列的使用场景"></a>阻塞队列的使用场景</h2><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 生产者消费者模式</span></span><br><span class="line">	</span><br><span class="line"><span class="meta">#</span><span class="bash"> 线程池</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 消息中间件</span></span><br></pre></td></tr></table></figure>

<h3 id="传统版生产者消费者模式-Demo"><a href="#传统版生产者消费者模式-Demo" class="headerlink" title="传统版生产者消费者模式 Demo"></a>传统版生产者消费者模式 Demo</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">package</span> ProducerAndConsumer;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 14:56</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述: 功能描述: 4个线程的if语句</span></span><br><span class="line"><span class="comment"> * 要求:生产者线程消费一个,消费者线程消费一个。num只能为1或0</span></span><br><span class="line"><span class="comment"> * 改用while循环的4个线程</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Producer_03</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Consumer3 consumer = <span class="keyword">new</span> Consumer3();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//生产者线程A</span></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.increment();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;生产者A&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.decrement();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;消费者B&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.increment();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;生产者C&quot;</span>).start();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    consumer.decrement();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;消费者D&quot;</span>).start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Consumer3</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Integer num = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">increment</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">while</span>(num != <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">this</span>.wait();</span><br><span class="line">        &#125;</span><br><span class="line">        num++;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + num);</span><br><span class="line">        notifyAll();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">decrement</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="keyword">while</span>(num == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">this</span>.wait();</span><br><span class="line">        &#125;</span><br><span class="line">        num--;</span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + num);</span><br><span class="line">        notifyAll();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="阻塞队列版生产者消费者模式Demo"><a href="#阻塞队列版生产者消费者模式Demo" class="headerlink" title="阻塞队列版生产者消费者模式Demo"></a>阻塞队列版生产者消费者模式Demo</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2019/9/26 16:04</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video44</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        MyResource myResource = <span class="keyword">new</span> MyResource(<span class="keyword">new</span> ArrayBlockingQueue&lt;&gt;(<span class="number">10</span>));</span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;----------生产者线程启动-----------&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                myResource.produce();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;Producer&quot;</span>).start();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">new</span> Thread(() -&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;----------消费者线程启动-----------&quot;</span>);</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                myResource.consume();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;,<span class="string">&quot;Consumer&quot;</span>).start();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        myResource.stop();</span><br><span class="line">        System.out.println(<span class="string">&quot;********5秒之后,main叫停生产,生产结束*********&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyResource</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> Boolean FLAG = Boolean.TRUE;</span><br><span class="line">    <span class="keyword">private</span> AtomicInteger atomicInteger = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line">    <span class="keyword">private</span> BlockingQueue&lt;String&gt; blockingQueue = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MyResource</span><span class="params">(BlockingQueue&lt;String&gt; blockingQueue)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.blockingQueue = blockingQueue;</span><br><span class="line">        <span class="comment">//打印日志一般需要看类信息</span></span><br><span class="line">        System.out.println(blockingQueue.getClass().getName());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">produce</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        String data = <span class="keyword">null</span>;</span><br><span class="line">        Boolean returnValue;</span><br><span class="line">        <span class="keyword">while</span>(FLAG)&#123;</span><br><span class="line">            data = atomicInteger.incrementAndGet() + <span class="string">&quot;&quot;</span>;</span><br><span class="line">            returnValue = blockingQueue.offer(data, <span class="number">2L</span>, TimeUnit.SECONDS);</span><br><span class="line">            <span class="keyword">if</span> (returnValue)&#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t\t 插入队列成功 \t&quot;</span> + data);</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 插入超时 \t&quot;</span> + data);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.MILLISECONDS.sleep(<span class="number">300</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 大老板叫停,生产者停止生产&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">consume</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        String data = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">while</span>(FLAG)&#123;</span><br><span class="line"><span class="comment">//            Thread.sleep(500);</span></span><br><span class="line">            data = blockingQueue.poll(<span class="number">2L</span>,TimeUnit.SECONDS);</span><br><span class="line">            <span class="keyword">if</span> (data == <span class="keyword">null</span> || data.equalsIgnoreCase(<span class="string">&quot;&quot;</span>))&#123;</span><br><span class="line">                FLAG = <span class="keyword">false</span>;</span><br><span class="line">                System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 消费超时,消费者退出&quot;</span> );</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 消费队列成功 \t&quot;</span> + data);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.FLAG = <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h1 id="线程池"><a href="#线程池" class="headerlink" title="线程池"></a>线程池</h1><h2 id="主要优点"><a href="#主要优点" class="headerlink" title="主要优点"></a>主要优点</h2><ul>
<li>第一:降低资源消耗.通过重复利用自己创建的线程降低线程创建和销毁造成的消耗.</li>
<li>第二: 提高响应速度.当任务到达时,任务可以不需要等到线程的创建，就能立即执行.</li>
<li>第三: 提高线程的可管理性.线程是稀缺资源,如果无限的创阿金,不仅会消耗资源,还会较低系统的稳定性,使用线程池可以进行统一分配,调优和监控.</li>
</ul>
<p>Java 中的线程池是通过 Executor 框架实现的，该框架中用到了 Executor、Executors、ExecutorService、ThreadPoolExecutor 这几个类。</p>
<h2 id="线程池七大参数入门简介"><a href="#线程池七大参数入门简介" class="headerlink" title="线程池七大参数入门简介"></a>线程池七大参数入门简介</h2><p><strong>流程举例</strong></p>
<p>一个银行网点 &lt;线程池&gt;，共 10* 个窗口 &lt;maximumPoolSize 最大线程数&gt;，开放 5* 个窗口 &lt;corePoolSize 核心线程数&gt;<br>。今天办理业务的特别多，其余5个窗口加班一天 &lt;keepAliveTime + unit 多余线程存活时间+单位&gt;，办理业务的人在窗口前排队* &lt;workQueue 请求任务的阻塞队列&gt;。银行<em>里的A</em>职员、B职员… 给办理业务 &lt;threadFactory 产生线程、线程名、线程序数…&gt;最多排10个，来了11个，并且每个窗口都有人在办理业务，多的人怎么拒绝呢？&lt;handler 拒绝策略&gt;</p>
<p><strong>七大参数</strong></p>
<ul>
<li><p>corePoolSize 线程池中的常驻核心线程数</p>
<pre><code> 创建线程池后，当有请求任务进来，就安排池中的线程去执行请求任务
   当线程池中的线程数目达到 corePoolSize 后，就会把到达的任务放到缓存队列中
</code></pre>
</li>
<li><p>maximumPoolSize<br>线程池能够容纳同时执行的最大线程数，此值必须大于等于1</p>
</li>
<li><p>keepAliveTime 多余的空闲线程的存活时间</p>
<pre><code> 当前线程池数量超过 corePoolSize 时，当空闲时间达到 keepAliveTime 值时，
  多余空闲线程会被销毁直到只剩下 corePoolSize 个线程为止
</code></pre>
</li>
<li><p>unit<br>keepAliveTime 的单位</p>
</li>
<li><p>workQueue<br>任务队列，被提交但尚未被执行的任务</p>
</li>
<li><p>threadFactory，表示生成线程池中工作线程的线程工厂&lt;线程名字、线程序数…&gt;，用于创建线程一般用默认的即可</p>
</li>
<li><p>handler，拒接策略，表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时，如何拒绝新的任务</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadPoolDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService threadPool =</span><br><span class="line">                <span class="keyword">new</span> ThreadPoolExecutor(<span class="number">2</span>,</span><br><span class="line">                        <span class="number">5</span>,</span><br><span class="line">                        <span class="number">1L</span>,</span><br><span class="line">                        TimeUnit.SECONDS,</span><br><span class="line">                        <span class="keyword">new</span> LinkedBlockingDeque&lt;Runnable&gt;(<span class="number">3</span>),</span><br><span class="line">                        Executors.defaultThreadFactory(),</span><br><span class="line">                        <span class="keyword">new</span> ThreadPoolExecutor.CallerRunsPolicy());</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>;i &lt;= <span class="number">9</span>; i++ )</span><br><span class="line">                threadPool.execute(() -&gt; &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 办理业务&quot;</span> );</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">1L</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="线程池的底层工作流程"><a href="#线程池的底层工作流程" class="headerlink" title="线程池的底层工作流程"></a>线程池的底层工作流程</h2><img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.8/Java_concurrency/Source_code/Third_stage/0003.png">

<p>1、创建线程池后，等待请求任务</p>
<p>2、当调用 execute() 方法添加请求任务时，线程池做如下判断</p>
<ul>
<li>如果正在运行的线程数量小于 corePoolSize，马上创建线程执行请求任务</li>
<li>如果正在运行的线程数量大于或等于 corePoolSize，将请求任务放入阻塞队列</li>
<li>如果阻塞队列满了，且正在运行的线程数小于 mamimumPoolSize,创建非核心线程执行请求任务</li>
<li>如果队列满了且线程池线程达到最大线程数，线程池启动饱和拒绝策略来执行</li>
</ul>
<p>3、当一个线程完成任务时，从阻塞队列中取出下一个任务来执行</p>
<p>4、当一个线程无事可做超过一定时间<keepAliveTime>时，线程池会判断</p>
<ul>
<li>如果当前运行的线程数大于 corePoolSize，该线程被销毁</li>
<li>所以，线程池完成所有请求任务后，最终会收缩到 corePoolSize 的大小</li>
</ul>
<h2 id="线程池的4种拒绝策略"><a href="#线程池的4种拒绝策略" class="headerlink" title="线程池的4种拒绝策略"></a>线程池的4种拒绝策略</h2><p> <strong>JDK 内置的拒绝策略</strong></p>
<ul>
<li><p>AbortPolicy(默认)</p>
<ul>
<li>直接抛出 RejectedExecutionException  异常阻止系统正常运行</li>
</ul>
</li>
<li><p>CallerRunsPolicy</p>
<ul>
<li>“调用者运行” 一种调节机制</li>
<li>该策略既不会抛弃任务，也不会抛出异常</li>
<li>而是将某些任务回退到调用者，从而降低新任务的流量</li>
</ul>
</li>
</ul>
<ul>
<li><p>DiscardOldestPolicy</p>
<ul>
<li>抛弃队列中等待最久的任务</li>
<li>然后把当前任务中加入队列中尝试再次提交当前任务</li>
</ul>
</li>
<li><p>DiscardPolicy</p>
<ul>
<li>直接丢弃任务，不予任何处理也不抛出异常</li>
<li>如果允许任务丢失，这是最好的一种方案</li>
</ul>
</li>
</ul>
<p> 以上拒绝策略都是实现了 RejectedExecutionHandler 接口</p>
<h2 id="线程池在实际生产中使用哪一个"><a href="#线程池在实际生产中使用哪一个" class="headerlink" title="线程池在实际生产中使用哪一个"></a>线程池在实际生产中使用哪一个</h2><blockquote>
<p>后文会介绍Java内置的几个线程池</p>
</blockquote>
<p> 阿里巴巴 Java 开发手册<br>     线程池不允许使用 Executors 创建，而是通过 ThreadPoolExecutor 的方式</p>
<p>FixedThreadPool 和 SingleThreadPool<br>         允许的阻塞队列容量为 Integer.MAX_VALUE，可能会堆积大量的请求，导致 OOM</p>
<p>CachedThreadPool 和 ScheduledThreadPool<br>         允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程，导致 OOM</p>
<h2 id="线程池合理配置参数"><a href="#线程池合理配置参数" class="headerlink" title="线程池合理配置参数"></a>线程池合理配置参数</h2><p><strong>1、CPU 密集型</strong><br>     意思是该任务需要大量的运算，而没有阻塞，CPU 一直全速运行<br>     CPU 密集任务只有在真正的多核 CPU 上才可能得到加速(通过多线程)<br>     CPU 密集型任务配置尽可能少的线程数量<br>     一般公式 : CPU 核数 + 1个线程的线程池最大线程数</p>
<p><strong>2、IO 密集型</strong><br>     由于 IO 密集型任务线程并不是一直在执行任务，则应配置尽可能多的线程<br>     一般公式 : CPU 核数* 2</p>
<p><strong>3、IO 密集型 2</strong><br>     IO 密集型、即该任务需要大量的 IO，即大量的堵塞<br>     在单线程上运行 IO 密集型的任务会导致浪费大量的 CPU 算力浪费在等待上<br>     所以，IO 密集型任务中使用多线程可以大大的加速程序运行，即时在单核 CPU 上<br>     这种加速主要就是利用了被浪费掉的阻塞时间<br>     参考公式 : CPU 核数 / (1 - 阻塞系数)<br>         例: 8 核CPU 8/(1-0.9) = 80 个线程数</p>
<h2 id="线程池的状态"><a href="#线程池的状态" class="headerlink" title="线程池的状态"></a>线程池的状态</h2><p><strong>线程池状态含义如下</strong></p>
<p>• RUNNING 接受新任务并且处理阻塞队列里的任务</p>
<p>• SHUTDOWN ：拒绝新任务但是处理阻塞队列里的任务</p>
<p>• STOP ：拒绝新任务并且放弃阻塞队列里的任务，同时会中断正在处理的任务。</p>
<p>• TIDYING：所有任务都执行完（包含阻塞队列里面的任务）后，当前线程池活动线程,数为0，将要调用 terminated 方法</p>
<p>• TERMINATED：终止状态，terminated 方法调用完成以后的状态</p>
<p><strong>线程池状态转换列举如下</strong></p>
<p>• RUNNING -&gt; SHUTDOWN 显式调用shutdown （） 方法 或者隐式调用了 finalize()方法里面的 shutdown（） 方法</p>
<p>• RUNNING或SHUTDOWN) -&gt; STOP 显式调用 shutdownNow（） 方法</p>
<p>• SHUTDOWN -&gt;TIDYING 当线程池和任务队列都为空时</p>
<p>• STOP -&gt; TIDYING 当线程池为空时</p>
<p>• TIDYING -&gt; TERMNATED terminated() hook 方法执行完成</p>
<h2 id="线程池的关闭"><a href="#线程池的关闭" class="headerlink" title="线程池的关闭"></a>线程池的关闭</h2><p>关闭有两个方法：<code>shutdown</code>和<code>shutdownNow</code></p>
<p><strong>shutdown</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">shutdown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> ReentrantLock mainLock = <span class="keyword">this</span>.mainLock;</span><br><span class="line">    mainLock.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        checkShutdownAccess();</span><br><span class="line">        advanceRunState(SHUTDOWN);</span><br><span class="line">        interruptIdleWorkers();</span><br><span class="line">        onShutdown(); <span class="comment">// hook for ScheduledThreadPoolExecutor</span></span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        mainLock.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">    tryTerminate();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">interruptIdleWorkers</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    interruptIdleWorkers(<span class="keyword">false</span>);</span><br><span class="line">&#125;  </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">interruptIdleWorkers</span><span class="params">(<span class="keyword">boolean</span> onlyOne)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> ReentrantLock mainLock = <span class="keyword">this</span>.mainLock;</span><br><span class="line">    mainLock.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (Worker w : workers) &#123;</span><br><span class="line">            Thread t = w.thread;</span><br><span class="line">            <span class="keyword">if</span> (!t.isInterrupted() &amp;&amp; w.tryLock()) &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    t.interrupt();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (SecurityException ignore) &#123;</span><br><span class="line">                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                    w.unlock();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (onlyOne)</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        mainLock.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li>从源码可以看出，本质上执行的是<code>interrupt</code>方法</li>
<li>如果线程是空闲的，执行的是Condition的await的方法，会被直接打断，被回收</li>
<li>如果正在工作，该线程会被打上一个标记，等任务执行后被回收</li>
</ul>
<p><strong>shutdownNow</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> List&lt;Runnable&gt; <span class="title">shutdownNow</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    List&lt;Runnable&gt; tasks;</span><br><span class="line">    <span class="keyword">final</span> ReentrantLock mainLock = <span class="keyword">this</span>.mainLock;</span><br><span class="line">    mainLock.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        checkShutdownAccess();</span><br><span class="line">        advanceRunState(STOP);</span><br><span class="line">        interruptWorkers();<span class="comment">//先打断</span></span><br><span class="line">        tasks = drainQueue();<span class="comment">//再把任务队列没有执行的任务取出</span></span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        mainLock.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">    tryTerminate();<span class="comment">//不断的打断</span></span><br><span class="line">    <span class="keyword">return</span> tasks;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>先打断空闲的打断</li>
<li>然后清空任务队列</li>
<li>然后不断的尝试打断正在执行的线程</li>
<li>最后会返回一个List集合，包含还没有执行的任务</li>
</ul>
<p><strong>awaitTermination 操作</strong></p>
<p>当线程调用<code>awaitTermination</code>方法后，当前线程会被阻塞，直到线程池状态变为TERMINATED 才返回 或者等待时间超时才返回。</p>
<h1 id="Executors"><a href="#Executors" class="headerlink" title="Executors"></a>Executors</h1><blockquote>
<p>内置线程池用的不多，不用太在意</p>
</blockquote>
<h2 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h2><p>Java通过Executors提供五种线程池，分别为：</p>
<ul>
<li><p><code>newCachedThreadPool</code>：创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。</p>
</li>
<li><p><code>newFixedThreadPool</code>：创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。</p>
</li>
<li><p><code>newScheduledThreadPool</code>：创建一个定长线程池，支持定时及周期性任务执行。</p>
<p><strong>和一个线程的区别</strong></p>
<table>
<thead>
<tr>
<th>newSingleThreadExecutor</th>
<th>Thread</th>
</tr>
</thead>
<tbody><tr>
<td>任务执行完成后，不会自动销毁，可以复用</td>
<td>任务执行完成后，会自动销毁</td>
</tr>
<tr>
<td>可以将任务存储在阻塞队列中，逐个执行</td>
<td>无法存储任务，只能执行一个任务</td>
</tr>
</tbody></table>
</li>
<li><p><code>newSingleThreadExecutor</code>：创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。</p>
</li>
<li><p><code>newWorkStealingPool</code>：创建一个ForkJoin线程池，线程数是CPU核数，可以充分利用CPU资源。从1.8开始有的</p>
</li>
</ul>
<p><strong>简单例子：</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Author</span>: youthlql-吕</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: 2020/4/23 10:49</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 功能描述: 线程池的三个常用方式</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video47</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 一池5个处理线程</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="comment">//ExecutorService threadPool= Executors.newFixedThreadPool(5);</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 一池一线程</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line"><span class="comment">//        ExecutorService threadPool= Executors.newSingleThreadExecutor();</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 一池N线程</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        ExecutorService threadPool = Executors.newCachedThreadPool();</span><br><span class="line">        <span class="comment">//模拟10个用户来办理业务 没有用户就是来自外部的请求线程.</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">20</span>; i++) &#123;</span><br><span class="line">                threadPool.execute(() -&gt; &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 办理业务&quot;</span>);</span><br><span class="line">                &#125;);</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.MICROSECONDS.sleep(<span class="number">200</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            threadPool.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>有三个内置线程池比较简单，下面介绍下稍复杂的两个内置线程池。</p>
<h2 id="newWorkStealingPool"><a href="#newWorkStealingPool" class="headerlink" title="newWorkStealingPool"></a>newWorkStealingPool</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title">newWorkStealingPool</span><span class="params">(<span class="keyword">int</span> parallelism)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ForkJoinPool</span><br><span class="line">        (parallelism,</span><br><span class="line">         ForkJoinPool.defaultForkJoinWorkerThreadFactory,</span><br><span class="line">         <span class="keyword">null</span>, <span class="keyword">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title">newWorkStealingPool</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ForkJoinPool</span><br><span class="line">        (Runtime.getRuntime().availableProcessors(),</span><br><span class="line">         ForkJoinPool.defaultForkJoinWorkerThreadFactory,</span><br><span class="line">         nul, <span class="keyword">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"> <span class="comment">//Returns the number of processors available to the Java virtual machine.</span></span><br><span class="line">    Runtime.getRuntime().availableProcessors()</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>分析源码我们可以得知</strong></p>
<ul>
<li>  采用的ForkJoin框架，可以将任务进行分割，同时线程之间会互相帮助</li>
<li>  最大的线程数是CPU核数，充分利用CPU资源</li>
</ul>
<h2 id="newScheduledThreadPool"><a href="#newScheduledThreadPool" class="headerlink" title="newScheduledThreadPool"></a>newScheduledThreadPool</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ScheduledExecutorService <span class="title">newScheduledThreadPool</span><span class="params">(<span class="keyword">int</span> corePoolSize)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ScheduledThreadPoolExecutor(corePoolSize);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<ul>
<li>  创建的是一个定时的任务，每隔一段时间就会运行一次</li>
</ul>
<p><strong>首先可以对比的就是Timer这个类</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExecutorsTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        Timer timer = <span class="keyword">new</span> Timer();</span><br><span class="line">        <span class="keyword">final</span> TimerTask task = <span class="keyword">new</span> TimerTask() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;=====&quot;</span> + System.currentTimeMillis());</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="comment">//1秒执行一次</span></span><br><span class="line">        timer.schedule(task,<span class="number">0</span>,<span class="number">1000</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong></p>
<pre><code>=====1602597314888
=====1602597316897
=====1602597318898
=====1602597320898
=====1602597322899
=====1602597324899
</code></pre>
<p>可以发现：<strong>如果任务时间超过了定时时长，就无法按照预定的时间执行</strong></p>
<p><strong>其他工具的解决方式</strong>：</p>
<ul>
<li>  <code>crontab</code>定时处理器<strong>为了确保时间的正确性，会重新启一个线程</strong></li>
</ul>
<p><strong>有三个方法</strong></p>
<ul>
<li><p>  schedule(commod,delay,unit) ，这个方法是说系统启动后，需要等待多久执行，delay是等待时间。只执行一次，没有周期性。</p>
</li>
<li><p>  scheduleAtFixedRate(commod,initialDelay,period,unit)，这个是以period为固定周期时间，按照一定频率来重复执行任务，initialDelay是说系统启动后，需要等待多久才开始执行。例如：如果设置了period为5秒，线程启动之后执行了大于5秒，线程结束之后，立即启动线程的下一次，如果线程启动之后只执行了3秒就结束了那执行下一次，需要等待2秒再执行。这个是优先保证任务执行的频率，</p>
</li>
<li><p>  scheduleWithFixedDelay(commod,initialDelay,delay,unit)，这个是以delay为固定延迟时间，按照一定的等待时间来执行任务，initialDelay意义与上面的相同。例如：设置了delay为5秒，线程启动之后不管执行了多久，结束之后都需要先生5秒，才能执行下一次。这个是优先保证任务执行的间隔。</p>
</li>
</ul>
<h1 id="ExecutorService"><a href="#ExecutorService" class="headerlink" title="ExecutorService"></a>ExecutorService</h1><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Video53</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ExecutorService threadPool = <span class="keyword">new</span> ThreadPoolExecutor(</span><br><span class="line">                <span class="number">2</span>,</span><br><span class="line">                <span class="number">5</span>,</span><br><span class="line">                <span class="number">1L</span>,</span><br><span class="line">                TimeUnit.SECONDS,</span><br><span class="line">                <span class="keyword">new</span> LinkedBlockingDeque&lt;Runnable&gt;(<span class="number">3</span>),</span><br><span class="line">                Executors.defaultThreadFactory(),</span><br><span class="line">                <span class="comment">//默认抛出异常</span></span><br><span class="line">                <span class="comment">//new ThreadPoolExecutor.AbortPolicy()</span></span><br><span class="line">                <span class="comment">//回退调用者</span></span><br><span class="line">                <span class="comment">//new ThreadPoolExecutor.CallerRunsPolicy()</span></span><br><span class="line">                <span class="comment">//处理不来的不处理</span></span><br><span class="line">                <span class="comment">//new ThreadPoolExecutor.DiscardOldestPolicy()</span></span><br><span class="line">                <span class="keyword">new</span> ThreadPoolExecutor.DiscardPolicy()</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">//模拟10个用户来办理业务 没有用户就是来自外部的请求线程.</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt;= <span class="number">10</span>; i++) &#123;</span><br><span class="line">                threadPool.execute(() -&gt; &#123;</span><br><span class="line">                    System.out.println(Thread.currentThread().getName() + <span class="string">&quot;\t 办理业务&quot;</span>);</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            threadPool.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//threadPoolInit();</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>ExecutorService一般就是用来作为我们自定义线程池的引用。</p>
<p><strong>API</strong></p>
<p>1、<code>getActiveCount()</code>：获取当前线程池中活跃的线程个数；若是没有<code>execute(Runnable)</code>任务的话，是不会创建线程的；提交一个任务，也只会创建一个线程去执行，而不会一次性直接创建<code>corePoolSize</code>个线程。</p>
<p>2、<code>allowCoreThreadTimeOut(true)</code>：当任务执行完成的时候，释放线程池；<strong>若使用的线程池的keepAliveTime为0，需要手动修改</strong>，因为不允许keepAliveTime为0的线程池，调用此方法；</p>
<p>3、<code>invokeAny(Call&lt;T&gt;)</code>：此方法是一个同步方法，会阻塞调用线程；若其中有一个任务返回了，则其它的任务取消，不会继续执行； 此方法也存在超时设置重构方法；防止线程一直等待；无法结束。</p>
<h1 id="Future"><a href="#Future" class="headerlink" title="Future"></a>Future</h1><h2 id="Future-API"><a href="#Future-API" class="headerlink" title="Future API"></a>Future API</h2><p>1、<code>get()</code>：此方法是阻塞的，但是抛出了InterruptedException，所以是可以被打断的；使用<code>interrupt()</code>进行打断的时候，打断的是调用get()的线程，让当前线程不再阻塞的等待获取数据；并不是真正执行任务的那个线程。</p>
<p>2、<code>get(TimeOut)</code>：若是获取数据超时了，但是任务还是依旧执行，只是不再等待任务的返回值。</p>
<p>3、<code>isDone()</code>：执行任务期间不管是否执行成功了，还是执行失败了（抛出异常）。只要结束，isDone()就会返回true。</p>
<p>4、<code>boolean cancel(boolean mayInterruptIfRunning)</code>：取消任务。</p>
<p>返回false的情况：1.任务已经执行完成了，是无法被取消的。2.之前已经被cancel过</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        testCancel();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testCancel</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">        <span class="comment">// 把线程设置为守护线程, 根据启动线程dead.</span></span><br><span class="line">        ExecutorService executorService = Executors.newCachedThreadPool();</span><br><span class="line">        AtomicBoolean running = <span class="keyword">new</span> AtomicBoolean(<span class="keyword">true</span>);</span><br><span class="line"></span><br><span class="line">        Future&lt;Integer&gt; future = executorService.submit(() -&gt; &#123;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">while</span> (running.get())&#123;</span><br><span class="line">                <span class="comment">//模拟一个执行很久的任务</span></span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;1111111&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">        System.out.println(future.cancel(<span class="keyword">true</span>));</span><br><span class="line">        System.out.println(future.isCancelled());</span><br><span class="line">        System.out.println(future.isDone());</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>输出：</p>
<p>true<br>true<br>true</p>
</blockquote>
<p>根据例子我们可以看到，cancel虽然取消了任务，但是任务任然在执行，这是为什么呢？</p>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/stephen8341/article/details/50433656">https://blog.csdn.net/stephen8341/article/details/50433656</a></p>
</blockquote>
<p>其实我们如果查看FutureTask的源码就会发现cancel只不过是调用了Thread的interrupt方法，而interrupt只能是停掉线程中有sleep,wait,join逻辑的线程，抛出一个InterruptException。这样看来FutureTask的cancel方法并不能停掉一切正在执行的异步任务。但是这里我们有一个妥协的做法就是在判断条件中加!Thread.currentThread().isInterrupted()这个判断即可.</p>
<p><strong>改进代码1</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testCance2</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">    <span class="comment">// 把线程设置为守护线程, 根据启动线程dead.</span></span><br><span class="line">    ExecutorService executorService = Executors.newCachedThreadPool();</span><br><span class="line"></span><br><span class="line">    Future&lt;Integer&gt; future = executorService.submit(() -&gt; &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (!Thread.interrupted())&#123;</span><br><span class="line">            <span class="comment">//模拟一个执行很久的任务</span></span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;1111111&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    TimeUnit.MILLISECONDS.sleep(<span class="number">500</span>);</span><br><span class="line">    System.out.println(future.cancel(<span class="keyword">true</span>));</span><br><span class="line">    System.out.println(future.isCancelled());</span><br><span class="line">    System.out.println(future.isDone());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>输出：</p>
<p>true<br>true<br>true<br>1111111</p>
</blockquote>
<p>可以看到任务是真正被终止了。</p>
<p>还有一个场景</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">while</span> (!Thread.interrupted())&#123;</span><br><span class="line">            <span class="comment">//模拟一个执行很久的任务</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上面改进代码的第一步，第一行代码是个IO操作，假设耗时非常长，那就根本没有机会判断while条件。此时如果cancel，一样不会真正的终止任务的执行。</p>
<p><strong>改进代码2</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">private static void testCance3() throws InterruptedException &#123;</span><br><span class="line">        &#x2F;&#x2F; 把线程设置为守护线程, 根据启动线程dead.</span><br><span class="line">        AtomicBoolean running &#x3D; new AtomicBoolean(true);</span><br><span class="line">        ExecutorService executorService &#x3D; Executors.newCachedThreadPool( r -&gt; &#123;</span><br><span class="line">            Thread t &#x3D; new Thread(r);</span><br><span class="line">            t.setDaemon(true);</span><br><span class="line">            return t;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        Future&lt;Integer&gt; future &#x3D; executorService.submit(() -&gt; &#123;</span><br><span class="line">&#x2F;&#x2F;            while (!Thread.interrupted())&#123;</span><br><span class="line">&#x2F;&#x2F;                &#x2F;&#x2F;模拟一个执行很久的任务</span><br><span class="line">&#x2F;&#x2F;            &#125;   </span><br><span class="line"></span><br><span class="line">            while (running.get())&#123;</span><br><span class="line">                &#x2F;&#x2F;模拟一个执行很久的任务</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            System.out.println(&quot;1111111&quot;);</span><br><span class="line">            return 10;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        TimeUnit.SECONDS.sleep(2);</span><br><span class="line">        System.out.println(future.cancel(true)); &#x2F;&#x2F; 可以取消掉任务, 但是无法终止任务的执行.</span><br><span class="line">        System.out.println(future.isCancelled());</span><br><span class="line">        System.out.println(future.isDone());</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>控制台输出：</p>
<p>true<br>true<br>true</p>
<p>Process finished with exit code 0</p>
</blockquote>
<p>可以看到直接结束了，思想就是将线程设置为守护线程，一旦主线程执行完，守护线程无论在干什么都会马上结束。所以后面的<code>System.out.println(&quot;1111111&quot;);</code>都没有打印</p>
<h2 id="已经被cancel的任务，是否还能拿到结果？"><a href="#已经被cancel的任务，是否还能拿到结果？" class="headerlink" title="已经被cancel的任务，是否还能拿到结果？"></a>已经被cancel的任务，是否还能拿到结果？</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">private static void testCance2() throws Exception &#123;</span><br><span class="line">    &#x2F;&#x2F; 把线程设置为守护线程, 根据启动线程dead.</span><br><span class="line">    ExecutorService executorService &#x3D; Executors.newCachedThreadPool();</span><br><span class="line"></span><br><span class="line">    Future&lt;Integer&gt; future &#x3D; executorService.submit(() -&gt; &#123;</span><br><span class="line"></span><br><span class="line">        while (!Thread.interrupted())&#123;</span><br><span class="line">            &#x2F;&#x2F;模拟一个执行很久的任务</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(&quot;1111111&quot;);</span><br><span class="line">        return 10;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    TimeUnit.MILLISECONDS.sleep(500);</span><br><span class="line">    System.out.println(future.cancel(true));</span><br><span class="line">    System.out.println(future.isCancelled());</span><br><span class="line">    System.out.println(future.isDone());</span><br><span class="line">    TimeUnit.SECONDS.sleep(1);</span><br><span class="line">    System.out.println(future.get());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>输出：</p>
<p>true<br>true<br>true<br>1111111<br>java.util.concurrent.CancellationException<br>    at java.util.concurrent.FutureTask.report(FutureTask.java:121)<br>    at java.util.concurrent.FutureTask.get(FutureTask.java:192)<br>    at Future.FutureExample1.testCance2(FutureExample1.java:63)<br>    at Future.FutureExample1.main(FutureExample1.java:19)</p>
</blockquote>
<p>输出了111111，说明程序已经走到了return那一行，但是可以看到拿不到了爆出了异常。</p>
<h2 id="Future的缺陷以及解决方案"><a href="#Future的缺陷以及解决方案" class="headerlink" title="Future的缺陷以及解决方案"></a>Future的缺陷以及解决方案</h2><p>1、缺陷一：使用Future可以保证任务的异步执行；但是，只要去获取任务的结果，就会导致程序的阻塞；从而，<strong>从异步再次变为了同步</strong>。</p>
<p>2、缺陷二：假设批量执行一些异步任务，大部分任务都是几秒完成的，有少许任务是几个小时才完成。那你get()的时候，万一拿到了几个小时执行的任务，就会一直阻塞，导致几秒完成的任务拿不到结果。</p>
<p>3、像netty会有回调的callback</p>
<p><strong>缺陷代码</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">futureExecSomeTask</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span>&#123;</span><br><span class="line">    ExecutorService executorService = Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line">    <span class="keyword">final</span> List&lt;Callable&lt;Integer&gt;&gt; callableList = Arrays.asList(            </span><br><span class="line">    		() -&gt; &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">10</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;Thread 10 finished!&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">            &#125;,</span><br><span class="line">            () -&gt; &#123;                </span><br><span class="line">            	TimeUnit.SECONDS.sleep(<span class="number">20</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;Thread 20 finished!&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="number">20</span>;</span><br><span class="line">            &#125;    </span><br><span class="line">     );</span><br><span class="line">	</span><br><span class="line">	<span class="comment">// invokeAll会阻塞等待所有的future执行完成.</span></span><br><span class="line">    List&lt;Future&lt;Integer&gt;&gt; futureList = executorService.invokeAll(callableList); </span><br><span class="line">    <span class="keyword">for</span> (Future&lt;Integer&gt; future : futureList) &#123;       </span><br><span class="line">    	 System.out.println(future.get());</span><br><span class="line">    &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<p><strong>JDK7解决方案</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">futureDefect</span><span class="params">()</span> <span class="keyword">throws</span> ExecutionException, InterruptedException </span>&#123;</span><br><span class="line">    ExecutorService executorService = Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">final</span> List&lt;Callable&lt;Integer&gt;&gt; callableList = Arrays.asList(            </span><br><span class="line">    		() -&gt; &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">10</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;Thread 10 finished!&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">            &#125;,</span><br><span class="line">            () -&gt; &#123;                </span><br><span class="line">            	TimeUnit.SECONDS.sleep(<span class="number">20</span>);</span><br><span class="line">                System.out.println(<span class="string">&quot;Thread 20 finished!&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span> <span class="number">20</span>;</span><br><span class="line">            &#125;    </span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    List&lt;Future&lt;Integer&gt;&gt; futureList = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    futureList.add(executorService.submit(callableList.get(<span class="number">0</span>)));</span><br><span class="line">    futureList.add(executorService.submit(callableList.get(<span class="number">1</span>)));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (Future&lt;Integer&gt; future : futureList) &#123;<span class="comment">// 其实相当于把批量任务, 单个的提交给线程池去执行.</span></span><br><span class="line">    	System.out.println(future.get());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>





<p><strong>JDK8解决方案</strong></p>
<p>CompletionService：具体见下面</p>
<h1 id="CompletionService"><a href="#CompletionService" class="headerlink" title="CompletionService"></a>CompletionService</h1><h2 id="简介-2"><a href="#简介-2" class="headerlink" title="简介"></a>简介</h2><ul>
<li><p>CompletionService的实现目标是任务先完成可优先获取到，即结果按照完成先后顺序排序。</p>
</li>
<li><p>ExecutorCompletionService类是常用的CompletionService实现类，该类只有三个成员变量：</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ExecutorCompletionService</span>&lt;<span class="title">V</span>&gt; <span class="keyword">implements</span> <span class="title">CompletionService</span>&lt;<span class="title">V</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Executor executor;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> AbstractExecutorService aes;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue&lt;Future&lt;V&gt;&gt; completionQueue;</span><br><span class="line">    ....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>可以看到ExecutorCompletionService主要是<strong>增强executor线程池的。</strong></li>
<li>Task包装后被塞入completionQueue，当Task结束，其Future就可以从completionQueue中获取到。</li>
</ul>
<p><strong>执行流程：</strong></p>
<img src= "" data-lazy-src="https://upyunimg.imlql.cn/youthlql@1.0.8/Java_concurrency/Source_code/Third_stage/0004.png">



<h2 id="阻塞和非阻塞获取"><a href="#阻塞和非阻塞获取" class="headerlink" title="阻塞和非阻塞获取"></a>阻塞和非阻塞获取</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Future&lt;V&gt; <span class="title">take</span><span class="params">()</span><span class="keyword">throws</span> InterruptedException</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Future&lt;V&gt; <span class="title">poll</span><span class="params">()</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Future&lt;V&gt; <span class="title">poll</span><span class="params">(<span class="keyword">long</span> timeout,TimeUnit unit)</span> <span class="keyword">throws</span> InterruptedException</span></span><br><span class="line"><span class="function">1234</span></span><br></pre></td></tr></table></figure>

<p><strong>阻塞获取</strong></p>
<p>take方法回使调用者阻塞，可以保证一定会有Future取出</p>
<p><strong>非阻塞获取</strong></p>
<p>poll方法会去查看是否有任务完成，有则取出；没有，就会返回一个null</p>
<h2 id="代码解决Future缺陷"><a href="#代码解决Future缺陷" class="headerlink" title="代码解决Future缺陷"></a>代码解决Future缺陷</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompletionServiceExample1</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            testCompleteExecutorService();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (ExecutionException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testCompleteExecutorService</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span>&#123;</span><br><span class="line">        ExecutorService executorService = Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line">        <span class="keyword">final</span> List&lt;Callable&lt;Integer&gt;&gt; callableList = Arrays.asList(</span><br><span class="line">                () -&gt; &#123;</span><br><span class="line">                    TimeUnit.MILLISECONDS.sleep(<span class="number">200</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;Thread 10 finished!&quot;</span>);</span><br><span class="line">                    <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">                &#125;,</span><br><span class="line">                () -&gt; &#123;</span><br><span class="line">                    TimeUnit.MILLISECONDS.sleep(<span class="number">400</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;Thread 20 finished!&quot;</span>);</span><br><span class="line">                    <span class="keyword">return</span> <span class="number">20</span>;</span><br><span class="line">                &#125;</span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 参数值为线程池对象.</span></span><br><span class="line">        ExecutorCompletionService&lt;Integer&gt; completionService = <span class="keyword">new</span> ExecutorCompletionService&lt;&gt;(executorService);</span><br><span class="line">        <span class="comment">// 提交需要执行的任务.</span></span><br><span class="line">        callableList.stream().forEach(item -&gt; completionService.submit(item));</span><br><span class="line"></span><br><span class="line">        Future&lt;Integer&gt; future;</span><br><span class="line">        <span class="comment">// 阻塞的获取任务结果. 但是, 不是等待全部任务完成, 而是, 完成一个任务, 获取一个任务结果.</span></span><br><span class="line">        <span class="keyword">while</span> ((future = completionService.take()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">            System.out.println(future.get());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//因为take阻塞住了，所以你是看不到下面这个打印的</span></span><br><span class="line">        System.out.println(<span class="string">&quot;Main is finished!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结果：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Thread 10 finished!</span><br><span class="line">10</span><br><span class="line">Thread 20 finished!</span><br><span class="line">20</span><br></pre></td></tr></table></figure>



<p>稍微改一下就可以打印出来了</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompletionServiceExample3</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            testCompleteExecutorService();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (ExecutionException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testCompleteExecutorService</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span>&#123;</span><br><span class="line">        ExecutorService executorService = Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line">        <span class="keyword">final</span> List&lt;Callable&lt;Integer&gt;&gt; callableList = Arrays.asList(</span><br><span class="line">                () -&gt; &#123;</span><br><span class="line">                    TimeUnit.MILLISECONDS.sleep(<span class="number">200</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;Thread 10 finished!&quot;</span>);</span><br><span class="line">                    <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">                &#125;,</span><br><span class="line">                () -&gt; &#123;</span><br><span class="line">                    TimeUnit.MILLISECONDS.sleep(<span class="number">400</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;Thread 20 finished!&quot;</span>);</span><br><span class="line">                    <span class="keyword">return</span> <span class="number">20</span>;</span><br><span class="line">                &#125;</span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 参数值为线程池对象.</span></span><br><span class="line">        ExecutorCompletionService&lt;Integer&gt; completionService = <span class="keyword">new</span> ExecutorCompletionService&lt;&gt;(executorService);</span><br><span class="line">        <span class="comment">// 提交需要执行的任务.</span></span><br><span class="line">        callableList.stream().forEach(item -&gt; completionService.submit(item));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> taskCount = callableList.size();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; taskCount; i++) &#123;</span><br><span class="line">            Integer result = completionService.take().get();</span><br><span class="line">            System.out.println(result);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">        System.out.println(<span class="string">&quot;Main is finished!&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//记得关闭线程池</span></span><br><span class="line">        executorService.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<p>结果：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Thread 10 finished!</span><br><span class="line">10</span><br><span class="line">Thread 20 finished!</span><br><span class="line">20</span><br><span class="line">Main is finished!</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure>





<h2 id="按完成顺序获取结果验证"><a href="#按完成顺序获取结果验证" class="headerlink" title="按完成顺序获取结果验证"></a>按完成顺序获取结果验证</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompletionServiceTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span>  </span>&#123;</span><br><span class="line">        Long start = System.currentTimeMillis();</span><br><span class="line">        <span class="comment">//开启3个线程</span></span><br><span class="line">        ExecutorService exs = Executors.newFixedThreadPool(<span class="number">5</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">int</span> taskCount = <span class="number">10</span>;</span><br><span class="line">            <span class="comment">// 结果集</span></span><br><span class="line">            List&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 1.定义CompletionService</span></span><br><span class="line">            CompletionService&lt;Integer&gt; completionService = <span class="keyword">new</span> ExecutorCompletionService&lt;Integer&gt;(exs);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 2.添加任务</span></span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;taskCount;i++)&#123;</span><br><span class="line">                completionService.submit(<span class="keyword">new</span> Task(i+<span class="number">1</span>));</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 3.获取结果</span></span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;taskCount;i++)&#123;</span><br><span class="line">                Integer result = completionService.take().get();</span><br><span class="line">                list.add(result);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            System.out.println(<span class="string">&quot;list=&quot;</span>+list);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="comment">//关闭线程池</span></span><br><span class="line">            exs.shutdown();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Task</span> <span class="keyword">implements</span> <span class="title">Callable</span>&lt;<span class="title">Integer</span>&gt; </span>&#123;</span><br><span class="line">        Integer i;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Task</span><span class="params">(Integer i)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>();</span><br><span class="line">            <span class="keyword">this</span>.i=i;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Integer <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(i==<span class="number">5</span>) &#123;</span><br><span class="line">                Thread.sleep(<span class="number">5000</span>);</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                Thread.sleep(<span class="number">1000</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程：&quot;</span>+Thread.currentThread().getName()+<span class="string">&quot;任务i=&quot;</span>+i+<span class="string">&quot;,执行完成！&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>控制台输出：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">线程：pool-1-thread-2任务i&#x3D;2,执行完成！</span><br><span class="line">线程：pool-1-thread-3任务i&#x3D;3,执行完成！</span><br><span class="line">线程：pool-1-thread-1任务i&#x3D;1,执行完成！</span><br><span class="line">线程：pool-1-thread-4任务i&#x3D;4,执行完成！</span><br><span class="line">线程：pool-1-thread-1任务i&#x3D;8,执行完成！</span><br><span class="line">线程：pool-1-thread-4任务i&#x3D;9,执行完成！</span><br><span class="line">线程：pool-1-thread-2任务i&#x3D;6,执行完成！</span><br><span class="line">线程：pool-1-thread-3任务i&#x3D;7,执行完成！</span><br><span class="line">线程：pool-1-thread-1任务i&#x3D;10,执行完成！</span><br><span class="line">线程：pool-1-thread-5任务i&#x3D;5,执行完成！</span><br><span class="line">list&#x3D;[2, 3, 1, 4, 8, 9, 6, 7, 10, 5]</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure>







<h1 id="CompleableFuture（重要，很常用）"><a href="#CompleableFuture（重要，很常用）" class="headerlink" title="CompleableFuture（重要，很常用）"></a>CompleableFuture（重要，很常用）</h1><h2 id="为什么会出现CompletableFuture？"><a href="#为什么会出现CompletableFuture？" class="headerlink" title="为什么会出现CompletableFuture？"></a>为什么会出现CompletableFuture？</h2><p>1、使用Future获得异步执行结果时，要么调用阻塞方法get()，要么轮询看isDone()是否为true，这两种方法都不是很好，因为主线程也会被迫等待。</p>
<p>2、从Java 8开始引入了CompletableFuture，它针对Future做了改进，可以传入回调对象，当异步任务完成或者发生异常时，自动调用回调对象的回调方法。</p>
<p><strong>优点：</strong></p>
<ul>
<li>可以利用结果进行级联的执行</li>
<li>支持callback会自动回调给调用者</li>
<li>执行一批任务时，可以按照任务执行的顺序，获得结果</li>
<li>可以并行的获取结果，只拿最先获取的结果级联的执行</li>
</ul>
<h2 id="简介及注意点"><a href="#简介及注意点" class="headerlink" title="简介及注意点"></a>简介及注意点</h2><p>1、CompletableFuture相当于是Future和ExecutorService的结合体，CompleableFuture依然是对Executor的封装，看构造函数的源码，可以知道一般情况下会创建一个ForkJoinPool，同时ThreadFactory<strong>会设置为守护线程</strong>。这就意味着：<code>一旦主线程结束，线程池就会关闭。</code>。可能导致回调函数还未执行, 便停止了。</p>
<p>如下：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompletableFutureTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line"></span><br><span class="line">        CompletableFuture.runAsync(()-&gt;&#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;).whenComplete((v,t)-&gt;&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;Done&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<p>控制台输出：</p>
<blockquote>
<p>Done</p>
</blockquote>
<p>2、可以改为此方法runAsync(Runnable, Executors), 让线程池去去管理线程. 不会跟随调用线程消失; 但是, 需要注意关闭线程池.</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">testrunAsync</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    ExecutorService threadPool = Executors.newFixedThreadPool(<span class="number">2</span>);</span><br><span class="line">    CompletableFuture.runAsync(() -&gt; &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;starting&quot;</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot;end!&quot;</span>);</span><br><span class="line"></span><br><span class="line">    &#125;, threadPool).whenComplete((v, t) -&gt; &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Finished!&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    System.out.println(<span class="string">&quot;All finished!&quot;</span>);</span><br><span class="line">    threadPool.shutdown();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>控制台输出：</p>
<blockquote>
<p>starting<br>All finished!<br>end!<br>Finished!</p>
<p>Process finished with exit code 0</p>
</blockquote>
<h2 id="构造CompleableFuture"><a href="#构造CompleableFuture" class="headerlink" title="构造CompleableFuture"></a>构造CompleableFuture</h2><p>创建<code>CompleableFuture</code>不建议使用构造方法，而是使用静态的工厂方法构建。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">allOf</span><span class="params">(CompletableFuture&lt;?&gt;... cfs)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Object&gt; <span class="title">anyOf</span><span class="params">(CompletableFuture&lt;?&gt;... cfs)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">completedFuture</span><span class="params">(U value)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">runAsync</span><span class="params">(Runnable runnable,Executor executor)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">runAsync</span><span class="params">(Runnable runnable)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">supplyAsync</span><span class="params">(Supplier&lt;U&gt; supplier)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">supplyAsync</span><span class="params">(Supplier&lt;U&gt; supplier, Executor executor)</span>                                                                      </span></span><br></pre></td></tr></table></figure>


<ul>
<li>  <code>allOf(CompletableFuture&lt;?&gt;... cfs)</code>：这个方法会返回一个全新的CompletableFuture，传递进去的所有CompletableFuture执行完才算是执行完成。</li>
<li>  <code>anyOf(CompletableFuture&lt;?&gt;... cfs)</code>：这个方法会返回一个全新的CompletableFuture，只要传递进去的有一个CompletableFuture执行完，就算是执行完成</li>
<li>  <code>completedFuture(U value)</code> ：可以假设一个执行出了一个结果，进行下面的级联操作。</li>
<li>  <code>runAsync</code>：异步的执行Runnable，没有返回值。</li>
<li>  <code>supplyAsync</code>：异步的执行Supplier实例，会有返回值。</li>
</ul>
<h3 id="runAsync"><a href="#runAsync" class="headerlink" title="runAsync"></a>runAsync</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">runAsync</span><span class="params">(Runnable runnable,Executor executor)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">runAsync</span><span class="params">(Runnable runnable)</span></span></span><br></pre></td></tr></table></figure>

<p>特点就是没有返回值，并且参数是<code>Runnable</code>。比一般的提交一个Runnable相比，可以更加灵活点使用，级联、并联等操作</p>
<p><strong>举例：</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_runAsync</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;main....start....&quot;</span>);</span><br><span class="line">        CompletableFuture&lt;Void&gt; future = CompletableFuture.runAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;当前线程：&quot;</span> + Thread.currentThread().getId());</span><br><span class="line">            <span class="keyword">int</span> i = <span class="number">10</span> / <span class="number">2</span>;</span><br><span class="line">            System.out.println(<span class="string">&quot;运行结果:&quot;</span> + i);</span><br><span class="line">        &#125;, executor);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//通过前面的睡眠5秒，也可以验证出，shutdown会处理已经在阻塞队列里的</span></span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">main....start....</span><br><span class="line">当前线程：12</span><br><span class="line">运行结果:5</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure>



<h3 id="supplyAsync"><a href="#supplyAsync" class="headerlink" title="supplyAsync"></a>supplyAsync</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;U&gt; <span class="function">CompletableFuture&lt;U&gt; <span class="title">supplyAsync</span><span class="params">(Supplier&lt;U&gt; supplier)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">supplyAsync</span><span class="params">(Supplier&lt;U&gt; supplier, Executor executor)</span> </span></span><br></pre></td></tr></table></figure>

<p>需要给<code>supplyAsync</code>提供一个Supplier</p>
<p><strong>举例：</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_supplyAsync</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ExecutionException, InterruptedException </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;main....start....&quot;</span>);</span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Integer&gt; future = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;当前线程：&quot;</span> + Thread.currentThread().getName());</span><br><span class="line">            <span class="keyword">int</span> i = <span class="number">10</span> / <span class="number">0</span>;</span><br><span class="line">            System.out.println(<span class="string">&quot;运行结果:&quot;</span> + i);</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125;, executor).whenComplete((res, excption) -&gt; &#123; <span class="comment">//虽然能得到异常信息，但是没法修改返回数据</span></span><br><span class="line">            System.out.println(<span class="string">&quot;异步任务成功完成了...结果是:&quot;</span> + res + <span class="string">&quot;；异常信息是&quot;</span> + excption);</span><br><span class="line">        &#125;).exceptionally(throwable -&gt; &#123;  <span class="comment">//可以感知异常，同时返回默认值</span></span><br><span class="line">            <span class="keyword">return</span> <span class="number">10</span>;</span><br><span class="line">        &#125;); <span class="comment">//成功以后干啥事</span></span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;future获取结果：&quot;</span> + future.get());</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Integer&gt; future1 = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;当前线程：&quot;</span> + Thread.currentThread().getName());</span><br><span class="line">            <span class="keyword">int</span> i = <span class="number">10</span> / <span class="number">4</span>;</span><br><span class="line">            System.out.println(<span class="string">&quot;运行结果:&quot;</span> + i);</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125;, executor).handle((res, thr) -&gt; &#123;</span><br><span class="line">            <span class="keyword">if</span> (res != <span class="keyword">null</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> res * <span class="number">2</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (thr != <span class="keyword">null</span>) &#123;  <span class="comment">//异常不等于空了，就返回0</span></span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;future1获取结果：&quot;</span> + future1.get());</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong>：</p>
<pre><code>main....start....
当前线程：pool-1-thread-1
异步任务成功完成了...结果是:null；异常信息是java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
future获取结果：10
当前线程：pool-1-thread-2
运行结果:2
future1获取结果：4

Process finished with exit code 0
</code></pre>
<h3 id="anyOf"><a href="#anyOf" class="headerlink" title="anyOf"></a>anyOf</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">public static CompletableFuture&lt;Object&gt; anyOf(CompletableFuture&lt;?&gt;... cfs)</span><br></pre></td></tr></table></figure>

<p><strong>举例：</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_anyOf</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; futureImg = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;查询商品的图片信息&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;hello.jpg&quot;</span>;</span><br><span class="line">        &#125;,executor);</span><br><span class="line">        CompletableFuture&lt;String&gt; futureAttr = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;查询商品的属性&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;黑色+256G&quot;</span>;</span><br><span class="line">        &#125;,executor);</span><br><span class="line">        CompletableFuture&lt;String&gt; futureDesc = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;查询商品的介绍&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;华为&quot;</span>;</span><br><span class="line">        &#125;,executor);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 1、因为anyOf是等待最早的一个CompletableFuture就能结束，所以返回值是最早执行完的那个任务。</span></span><br><span class="line"><span class="comment">         * 2、直接通过原来的future.get()可能会有空指针异常</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        CompletableFuture&lt;Object&gt; anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);</span><br><span class="line">        anyOf.get();<span class="comment">//等待所有结果完成</span></span><br><span class="line">        System.out.println(<span class="string">&quot;最早完成的任务返回值为：&quot;</span>+anyOf.get());</span><br><span class="line"></span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果：</strong></p>
<pre><code>查询商品的介绍
最早完成的任务返回值为：华为
查询商品的图片信息
查询商品的属性
</code></pre>
<p>这个例子中，前两个<code>CompletableFuture</code>都睡了两秒，所以执行最快的肯定是第三个，从结果中也得到了验证。</p>
<p>需要注意一点，虽然是异步的从一个地方取值，但是其他任务依然会执行完成，而并非不再执行了。</p>
<h3 id="allOf"><a href="#allOf" class="headerlink" title="allOf"></a>allOf</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> CompletableFuture&lt;Void&gt; <span class="title">allOf</span><span class="params">(CompletableFuture&lt;?&gt;... cfs)</span></span></span><br></pre></td></tr></table></figure>



<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_allOf</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; futureImg = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;查询商品的图片信息&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;hello.jpg&quot;</span>;</span><br><span class="line">        &#125;, executor);</span><br><span class="line">        CompletableFuture&lt;String&gt; futureAttr = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;查询商品的属性&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;黑色+256G&quot;</span>;</span><br><span class="line">        &#125;, executor);</span><br><span class="line">        CompletableFuture&lt;String&gt; futureDesc = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;查询商品的介绍&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;华为&quot;</span>;</span><br><span class="line">        &#125;, executor);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;等待Future返回------&quot;</span>);</span><br><span class="line">        <span class="comment">//因为allOf是等待所有CompletableFuture完成才能结束，所以没有返回值，直接通过原来的future.get()就一定会有返回值</span></span><br><span class="line">        CompletableFuture&lt;Void&gt; allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);</span><br><span class="line">        System.out.println(<span class="string">&quot;最终得到的结果：&quot;</span> + futureImg.get() + <span class="string">&quot;=&gt;&quot;</span> + futureAttr.get() + <span class="string">&quot;=&gt;&quot;</span> + futureDesc.get());</span><br><span class="line"></span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结果：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">等待Future返回------</span><br><span class="line">查询商品的图片信息</span><br><span class="line">查询商品的介绍</span><br><span class="line">查询商品的属性</span><br><span class="line">最终得到的结果：hello.jpg&#x3D;&gt;黑色+256G&#x3D;&gt;华为</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure>



<h2 id="组合方法"><a href="#组合方法" class="headerlink" title="组合方法"></a>组合方法</h2><h3 id="组合两个任务，同时处理两个结果"><a href="#组合两个任务，同时处理两个结果" class="headerlink" title="组合两个任务，同时处理两个结果"></a>组合两个任务，同时处理两个结果</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;U&gt; <span class="function">CompletableFuture&lt;Void&gt; <span class="title">thenAcceptBoth</span><span class="params">(CompletionStage&lt;? extends U&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                  BiConsumer&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> U&gt; action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;Void&gt; <span class="title">thenAcceptBothAsync</span><span class="params">(CompletionStage&lt;? extends U&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                       BiConsumer&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> U&gt; action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;Void&gt; <span class="title">thenAcceptBothAsync</span><span class="params">(CompletionStage&lt;? extends U&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                       BiConsumer&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> U&gt; action,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                       Executor executor)</span></span></span><br></pre></td></tr></table></figure>




<p><strong>举例</strong>：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_Accept</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture1 = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;我是任务1&quot;</span>);</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture2 = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;我是任务2&quot;</span>);</span><br><span class="line">        completableFuture1.thenAcceptBothAsync(completableFuture2, (s, i) -&gt; &#123;</span><br><span class="line">            System.out.println(s + <span class="string">&quot;==&gt;&quot;</span> + i);</span><br><span class="line">        &#125;, executor);</span><br><span class="line"></span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong>：</p>
<pre><code>我是任务1==&gt;我是任务2

Process finished with exit code 0
</code></pre>
<p><strong>分析</strong></p>
<ul>
<li>  可以看出是两个任务组合，然后同时将两个结果一起处理</li>
</ul>
<h3 id="组合两个任务，任务完成后做的操作"><a href="#组合两个任务，任务完成后做的操作" class="headerlink" title="组合两个任务，任务完成后做的操作"></a>组合两个任务，任务完成后做的操作</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">runAfterBoth</span><span class="params">(CompletionStage&lt;?&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                            Runnable action)</span>                                            </span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">runAfterBothAsync</span><span class="params">(CompletionStage&lt;?&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                 Runnable action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">runAfterBothAsync</span><span class="params">(CompletionStage&lt;?&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                 Runnable action)</span></span></span><br></pre></td></tr></table></figure>



<h3 id="当两个任务任意一个执行完成后，执行一个操作"><a href="#当两个任务任意一个执行完成后，执行一个操作" class="headerlink" title="当两个任务任意一个执行完成后，执行一个操作"></a>当两个任务任意一个执行完成后，执行一个操作</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">runAfterEither</span><span class="params">(CompletionStage&lt;?&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                              Runnable action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">runAfterEitherAsync</span><span class="params">(CompletionStage&lt;?&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                   Runnable action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">runAfterEitherAsync</span><span class="params">(CompletionStage&lt;?&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                   Runnable action,Executor executor)</span>)</span></span><br></pre></td></tr></table></figure>

<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_runAfterEither</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;我是任务1&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;a&quot;</span>;</span><br><span class="line">        &#125;,executor);</span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Void&gt; future = completableFuture.runAfterEitherAsync(CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;我是任务2&quot;</span>);</span><br><span class="line">                    <span class="keyword">return</span> <span class="string">&quot;b&quot;</span>;</span><br><span class="line">                &#125;),</span><br><span class="line">                () -&gt; System.out.println(<span class="string">&quot;两个任务执行完，我才执行&quot;</span>),executor);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;end&quot;</span>);</span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong>：</p>
<pre><code>我是任务1
我是任务2
end
两个任务执行完，我才执行

Process finished with exit code 0
</code></pre>
<h3 id="组合两个任务，处理后，返回一个结果"><a href="#组合两个任务，处理后，返回一个结果" class="headerlink" title="组合两个任务，处理后，返回一个结果"></a>组合两个任务，处理后，返回一个结果</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;U,V&gt; <span class="function">CompletableFuture&lt;V&gt; <span class="title">thenCombine</span><span class="params">(CompletionStage&lt;? extends U&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                              BiFunction&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> U,? extends V&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U,V&gt; CompletableFuture&lt;V&gt; <span class="title">thenCombineAsync</span><span class="params">(CompletionStage&lt;? extends U&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                   BiFunction&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> U,? extends V&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U,V&gt; CompletableFuture&lt;V&gt; <span class="title">thenCombineAsync</span><span class="params">(CompletionStage&lt;? extends U&gt; other,</span></span></span><br><span class="line"><span class="function"><span class="params">                                                   BiFunction&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> U,? extends V&gt; fn,, Executor executor)</span></span></span><br></pre></td></tr></table></figure>


<p>​    </p>
<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_thenCombine</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;a&quot;</span>);</span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Boolean&gt; future = completableFuture.thenCombineAsync(CompletableFuture.supplyAsync(() -&gt; <span class="number">100</span>),</span><br><span class="line">                (s, i) -&gt; &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;s: &quot;</span> + s + <span class="string">&quot; , i : &quot;</span> + i);</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">                &#125;, executor);</span><br><span class="line">        System.out.println(future.get());</span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>结果</strong>：</p>
<pre><code>s: a , i : 100
true

Process finished with exit code 0
</code></pre>
<h3 id="第一个任务的输出是第二个任务的输入"><a href="#第一个任务的输出是第二个任务的输入" class="headerlink" title="第一个任务的输出是第二个任务的输入"></a>第一个任务的输出是第二个任务的输入</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;U&gt; <span class="function">CompletableFuture&lt;U&gt; <span class="title">thenCompose</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends CompletionStage&lt;U&gt;&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">thenComposeAsync</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends CompletionStage&lt;U&gt;&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">thenComposeAsync</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends CompletionStage&lt;U&gt;&gt; fn, Executor executor)</span></span></span><br></pre></td></tr></table></figure>

<p>相当于一次级联操作</p>
<p>举例：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_thenCompose</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * public &lt;U&gt; CompletableFuture&lt;U&gt; thenComposeAsync(Function&lt;? super T,? extends CompletionStage&lt;U&gt;&gt; fn, Executor executor)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture1 = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;我是任务1&quot;</span>);</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture2 = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;我是任务2&quot;</span>);</span><br><span class="line">        CompletableFuture&lt;String&gt; future = completableFuture1.thenComposeAsync(s -&gt; completableFuture2, executor);</span><br><span class="line">        System.out.println(future.get());</span><br><span class="line"></span><br><span class="line">        executor.shutdown();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">我是任务2</span><br><span class="line"></span><br><span class="line">Process finished with exit code 0</span><br></pre></td></tr></table></figure>

<h2 id="中转方法"><a href="#中转方法" class="headerlink" title="中转方法"></a>中转方法</h2><h3 id="有返回值"><a href="#有返回值" class="headerlink" title="有返回值"></a>有返回值</h3><h4 id="当执行完成时执行的操作"><a href="#当执行完成时执行的操作" class="headerlink" title="当执行完成时执行的操作"></a>当执行完成时执行的操作</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;T&gt; <span class="title">whenComplete</span><span class="params">(BiConsumer&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> Throwable&gt; action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;T&gt; <span class="title">whenCompleteAsync</span><span class="params">(BiConsumer&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> Throwable&gt; action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;T&gt; <span class="title">whenCompleteAsync</span><span class="params">(BiConsumer&lt;? <span class="keyword">super</span> T,? <span class="keyword">super</span> Throwable&gt; action, Executor executor)</span></span></span><br></pre></td></tr></table></figure>


<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_whenComplete</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;Hello&quot;</span>);</span><br><span class="line">        CompletableFuture&lt;String&gt; future = completableFuture.whenComplete((v, t)</span><br><span class="line">                -&gt; &#123;</span><br><span class="line">            System.out.println(v + <span class="string">&quot; World !&quot;</span>);</span><br><span class="line">            <span class="comment">//这个t是Throwable，只有报错了才会打印</span></span><br><span class="line">            System.out.println(t);</span><br><span class="line">        &#125;);</span><br><span class="line">        System.out.println(<span class="string">&quot;future:&quot;</span> + future.get());</span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>




<p>​    </p>
<p><strong>结果</strong></p>
<pre><code>Hello World !
Hello
</code></pre>
<p><strong>分析</strong></p>
<ul>
<li><p>当执行完成时执行的回调方法</p>
</li>
<li><p>该方法会接收执行的结果以及异常</p>
</li>
<li><p>回调完成会，会把原来任务执行的结果传递回去</p>
</li>
<li><p>whenCompleteAsync是异步的；whenComplete是同步的，会卡住主线程</p>
</li>
<li><p>需要传递一个<code>BiConsumer</code>接口，如下所示：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;T&gt; <span class="title">whenComplete</span><span class="params">(BiConsumer&lt;? <span class="keyword">super</span> T, ? <span class="keyword">super</span> Throwable&gt; action)</span>l</span>;</span><br></pre></td></tr></table></figure></li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">BiConsumer</span>&lt;<span class="title">T</span>, <span class="title">U</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">accept</span><span class="params">(T t, U u)</span></span>;</span><br><span class="line"> ｝</span><br></pre></td></tr></table></figure>



<ul>
<li>T是执行的结果，U是执行时产生的异常</li>
</ul>
<h4 id="级联操作"><a href="#级联操作" class="headerlink" title="级联操作"></a>级联操作</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;U&gt; <span class="function">CompletableFuture&lt;U&gt; <span class="title">thenApply</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends U&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">thenApplyAsync</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends U&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">thenApplyAsync</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends U&gt; fn,Executor executor)</span></span></span><br></pre></td></tr></table></figure>


<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_thenApplyAsync</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;Hello&quot;</span>);</span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Integer&gt; future = completableFuture.thenApplyAsync(t -&gt; &#123;</span><br><span class="line">            String s = t + <span class="string">&quot; World !&quot;</span>;</span><br><span class="line">            System.out.println(s);</span><br><span class="line">            <span class="keyword">return</span> s.length();</span><br><span class="line">        &#125;);</span><br><span class="line">        System.out.println(future.get());</span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;U&gt; <span class="function">CompletableFuture&lt;U&gt; <span class="title">thenApplyAsync</span><span class="params">(Function&lt;? <span class="keyword">super</span> T,? extends U&gt; fn)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Function</span>&lt;<span class="title">T</span>, <span class="title">R</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function">R <span class="title">apply</span><span class="params">(T t)</span></span>;</span><br><span class="line">｝</span><br></pre></td></tr></table></figure>

<p><strong>结果</strong></p>
<pre><code>Hello World !
13

Process finished with exit code -1
</code></pre>
<p><strong>分析</strong></p>
<ul>
<li>  是一个级联操作，即拿着上个任务的结果，做下个任务，同时返回一个新的结果</li>
</ul>
<h4 id="处理结果的操作"><a href="#处理结果的操作" class="headerlink" title="处理结果的操作"></a>处理结果的操作</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> &lt;U&gt; <span class="function">CompletableFuture&lt;U&gt; <span class="title">handle</span><span class="params">(BiFunction&lt;? <span class="keyword">super</span> T,Throwable,? extends U&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">handleAsync</span><span class="params">(BiFunction&lt;? <span class="keyword">super</span> T,Throwable,? extends U&gt; fn)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> &lt;U&gt; CompletableFuture&lt;U&gt; <span class="title">handleAsync</span><span class="params">(BiFunction&lt;? <span class="keyword">super</span> T,Throwable,? extends U&gt; fn,Executor executor)</span></span></span><br></pre></td></tr></table></figure>


<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompletableFutureTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;Hello&quot;</span>);</span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Integer&gt; future = completableFuture.handleAsync((s,t) -&gt; &#123;</span><br><span class="line">            String aaa =  t + <span class="string">&quot; World !&quot;</span>;</span><br><span class="line">            System.out.println(aaa);</span><br><span class="line">            <span class="keyword">return</span> aaa.length();</span><br><span class="line">        &#125;);</span><br><span class="line">        System.out.println(future.get());</span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong>：</p>
<pre><code>Hello World !
13
</code></pre>
<p><strong>分析</strong>：</p>
<ul>
<li>  相比于<code>whenComplete</code>返回值可以自己处理，相当于一次级联</li>
<li>  相比于<code>thenApply</code>，可以处理异常</li>
</ul>
<h3 id="无返回值"><a href="#无返回值" class="headerlink" title="无返回值"></a>无返回值</h3><h4 id="处理结果"><a href="#处理结果" class="headerlink" title="处理结果"></a>处理结果</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">thenAccept</span><span class="params">(Consumer&lt;? <span class="keyword">super</span> T&gt; action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">thenAcceptAsync</span><span class="params">(Consumer&lt;? <span class="keyword">super</span> T&gt; action)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> CompletableFuture&lt;Void&gt; <span class="title">thenAcceptAsync</span><span class="params">(Consumer&lt;? <span class="keyword">super</span> T&gt; action,Executor executor)</span></span></span><br></pre></td></tr></table></figure>


<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CompletableFutureTest</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; <span class="string">&quot;Hello&quot;</span>);</span><br><span class="line"></span><br><span class="line">        CompletableFuture&lt;Void&gt; future = completableFuture.thenAccept(t -&gt; &#123;</span><br><span class="line">            String aaa =  t + <span class="string">&quot; World !&quot;</span>;</span><br><span class="line">            System.out.println(aaa);</span><br><span class="line">        &#125;);</span><br><span class="line">        System.out.println(future.get());</span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p><strong>结果</strong></p>
<pre><code>Hello World !
null
</code></pre>
<p><strong>分析</strong></p>
<ul>
<li>  相当于一次级联，但是没有返回值</li>
</ul>
<h4 id="执行完全部任务"><a href="#执行完全部任务" class="headerlink" title="执行完全部任务"></a>执行完全部任务</h4><pre><code>public CompletableFuture&lt;Void&gt; thenRun(Runnable action)
public CompletableFuture&lt;Void&gt; thenRunAsync(Runnable action)
public CompletableFuture&lt;Void&gt; thenRunAsync(Runnable action,Executor executor)
</code></pre>
<p><strong>分析</strong></p>
<ul>
<li>  相较<code>thenAccept</code>，不处理任务的执行结果</li>
</ul>
<h2 id="终结方法"><a href="#终结方法" class="headerlink" title="终结方法"></a>终结方法</h2><h4 id="处理异常"><a href="#处理异常" class="headerlink" title="处理异常"></a>处理异常</h4><pre><code>public CompletableFuture&lt;T&gt; exceptionally(Function&lt;Throwable,? extends T&gt; fn)
</code></pre>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_exceptionally</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(() -&gt; &#123;</span><br><span class="line">            <span class="keyword">int</span> a = <span class="number">1</span> / <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;World &quot;</span>;</span><br><span class="line">        &#125;);</span><br><span class="line">        completableFuture.exceptionally(Throwable::getMessage).thenAccept(t -&gt; &#123;</span><br><span class="line">            System.out.println(t);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><strong>结果：</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">java.lang.ArithmeticException: &#x2F; by zero</span><br><span class="line"></span><br><span class="line">Process finished with exit code -1</span><br></pre></td></tr></table></figure>



<h4 id="立马获取结果"><a href="#立马获取结果" class="headerlink" title="立马获取结果"></a>立马获取结果</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> T <span class="title">getNow</span><span class="params">(T valueIfAbsent)</span></span></span><br></pre></td></tr></table></figure>

<p><strong>举例</strong></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Test_getNow</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        CompletableFuture&lt;String&gt; completableFuture = CompletableFuture.supplyAsync(</span><br><span class="line">                () -&gt; &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                        e.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">return</span> <span class="string">&quot;World&quot;</span>;</span><br><span class="line">                &#125;);</span><br><span class="line"></span><br><span class="line">        </span><br><span class="line">        String now = completableFuture.getNow(<span class="string">&quot;Hello&quot;</span>);</span><br><span class="line">        System.out.println(now);</span><br><span class="line">        System.out.println(completableFuture.get());</span><br><span class="line">        Thread.currentThread().join();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><strong>结果</strong></p>
<pre><code>Hello
World

Process finished with exit code -1
</code></pre>
<p><strong>分析</strong></p>
<ul>
<li>  如果结果完成返回结果，如果未完成，返回传入进去的值</li>
</ul>
<h4 id="判断结果是否完成，如果未完成则赋予结果"><a href="#判断结果是否完成，如果未完成则赋予结果" class="headerlink" title="判断结果是否完成，如果未完成则赋予结果"></a>判断结果是否完成，如果未完成则赋予结果</h4><pre><code>public boolean complete(T value)
</code></pre>
<h4 id="判断结果是否完成，如果未完成返回异常"><a href="#判断结果是否完成，如果未完成返回异常" class="headerlink" title="判断结果是否完成，如果未完成返回异常"></a>判断结果是否完成，如果未完成返回异常</h4><pre><code>public boolean completeExceptionally(Throwable ex)
</code></pre>
<h4 id="后续获取结果会产生异常"><a href="#后续获取结果会产生异常" class="headerlink" title="后续获取结果会产生异常"></a>后续获取结果会产生异常</h4><pre><code>public void obtrudeException(Throwable ex)
</code></pre>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul>
<li>  <code>thenAccept</code>()处理正常结果；</li>
<li>  <code>exceptionally</code>()处理异常结果；</li>
<li>  <code>thenApplyAsync</code>()用于串行化另一个<code>CompletableFuture</code>；</li>
<li>  <code>anyOf</code>()和<code>allOf</code>()用于并行化多个<code>CompletableFuture</code>。</li>
</ul>
<h1 id="参考："><a href="#参考：" class="headerlink" title="参考："></a>参考：</h1><p>《Java并发编程之美》</p>
<p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/yuandengta/p/12887361.html">https://www.cnblogs.com/yuandengta/p/12887361.html</a></p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">youthlql</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://imlql.cn/post/70c90e5d.html">https://imlql.cn/post/70c90e5d.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://imlql.cn" target="_blank">风祈的时光录</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Java%E5%B9%B6%E5%8F%91/">Java并发</a><a class="post-meta__tags" href="/tags/%E5%8E%9F%E7%90%86/">原理</a><a class="post-meta__tags" href="/tags/%E6%BA%90%E7%A0%81/">源码</a></div><div class="post_share"></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="https://npm.elemecdn.com/youthlql@1.0.8/blog/wechat.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="https://npm.elemecdn.com/youthlql@1.0.8/blog/wechat.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="https://npm.elemecdn.com/youthlql@1.0.8/blog/alipay.jpg" target="_blank"><img class="post-qr-code-img" src= "" data-lazy-src="https://npm.elemecdn.com/youthlql@1.0.8/blog/alipay.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/post/de3879ae.html"><img class="prev-cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/java.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">详解JDK8新特性</div></div></a></div><div class="next-post pull-right"><a href="/post/5be45d9e.html"><img class="next-cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Java并发体系-第三阶段-JUC并发包-[1]</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/post/8210870.html" title="Java并发体系-第二阶段-锁与同步-[2]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-07</div><div class="title">Java并发体系-第二阶段-锁与同步-[2]</div></div></a></div><div><a href="/post/230c5bb3.html" title="Java并发体系-第二阶段-锁与同步-[1]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-06</div><div class="title">Java并发体系-第二阶段-锁与同步-[1]</div></div></a></div><div><a href="/post/5be45d9e.html" title="Java并发体系-第三阶段-JUC并发包-[1]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-09</div><div class="title">Java并发体系-第三阶段-JUC并发包-[1]</div></div></a></div><div><a href="/post/113a3931.html" title="Java并发体系-第二阶段-锁与同步-[3]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-08</div><div class="title">Java并发体系-第二阶段-锁与同步-[3]</div></div></a></div><div><a href="/post/efc79183.html" title="Java并发体系-第一阶段-多线程基础知识"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-05</div><div class="title">Java并发体系-第一阶段-多线程基础知识</div></div></a></div><div><a href="/post/92c4503d.html" title="Java并发体系-第四阶段-AQS源码解读-[1]"><img class="cover" src= "" data-lazy-src="https://upyunimg.imlql.cn/lql_static@latest/logo/Java_concurrency.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-26</div><div class="title">Java并发体系-第四阶段-AQS源码解读-[1]</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#Phaser%E5%B7%A5%E5%85%B7"><span class="toc-text">Phaser工具</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%87%8D%E5%A4%8D%E4%BD%BF%E7%94%A8%E7%9A%84%E4%BE%8B%E5%AD%90"><span class="toc-text">重复使用的例子</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E5%87%8F%E5%B0%91"><span class="toc-text">动态减少</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8API"><span class="toc-text">常用API</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B3%A8%E5%86%8C"><span class="toc-text">注册</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%B0%E8%BE%BE"><span class="toc-text">到达</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#onAdvance"><span class="toc-text">onAdvance()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%9B%91%E6%8E%A7%E5%AD%90%E7%BA%BF%E7%A8%8B%E4%BB%BB%E5%8A%A1"><span class="toc-text">监控子线程任务</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BC%BA%E5%88%B6%E5%85%B3%E9%97%AD"><span class="toc-text">强制关闭</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%9B%91%E6%8E%A7API"><span class="toc-text">监控API</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%8E%B7%E5%8F%96%E9%98%B6%E6%AE%B5%E6%95%B0"><span class="toc-text">获取阶段数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%8E%B7%E5%8F%96%E6%B3%A8%E5%86%8C%E7%9A%84%E6%95%B0"><span class="toc-text">获取注册的数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%8E%B7%E5%BE%97%E5%88%B0%E8%BE%BE%E5%92%8C%E6%9C%AA%E5%88%B0%E8%BE%BE%E7%9A%84%E6%95%B0%E7%9B%AE"><span class="toc-text">获得到达和未到达的数目</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Phaser%E7%9A%84%E5%88%86%E5%B1%82%E7%BB%93%E6%9E%84"><span class="toc-text">Phaser的分层结构</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97"><span class="toc-text">阻塞队列</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%AF%B7%E8%B0%88%E8%B0%88%E5%AF%B9%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E7%9A%84%E7%90%86%E8%A7%A3"><span class="toc-text">请谈谈对阻塞队列的理解</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%A7%8D%E7%B1%BB"><span class="toc-text">种类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%A0%B8%E5%BF%83%E6%96%B9%E6%B3%95"><span class="toc-text">核心方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">阻塞队列的使用场景</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BC%A0%E7%BB%9F%E7%89%88%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F-Demo"><span class="toc-text">传统版生产者消费者模式 Demo</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E7%89%88%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8FDemo"><span class="toc-text">阻塞队列版生产者消费者模式Demo</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0"><span class="toc-text">线程池</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BB%E8%A6%81%E4%BC%98%E7%82%B9"><span class="toc-text">主要优点</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%83%E5%A4%A7%E5%8F%82%E6%95%B0%E5%85%A5%E9%97%A8%E7%AE%80%E4%BB%8B"><span class="toc-text">线程池七大参数入门简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E5%BA%95%E5%B1%82%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B"><span class="toc-text">线程池的底层工作流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%844%E7%A7%8D%E6%8B%92%E7%BB%9D%E7%AD%96%E7%95%A5"><span class="toc-text">线程池的4种拒绝策略</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%9C%A8%E5%AE%9E%E9%99%85%E7%94%9F%E4%BA%A7%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%80%E4%B8%AA"><span class="toc-text">线程池在实际生产中使用哪一个</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%90%88%E7%90%86%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0"><span class="toc-text">线程池合理配置参数</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E7%8A%B6%E6%80%81"><span class="toc-text">线程池的状态</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E5%85%B3%E9%97%AD"><span class="toc-text">线程池的关闭</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Executors"><span class="toc-text">Executors</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-1"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#newWorkStealingPool"><span class="toc-text">newWorkStealingPool</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#newScheduledThreadPool"><span class="toc-text">newScheduledThreadPool</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#ExecutorService"><span class="toc-text">ExecutorService</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#Future"><span class="toc-text">Future</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#Future-API"><span class="toc-text">Future API</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B7%B2%E7%BB%8F%E8%A2%ABcancel%E7%9A%84%E4%BB%BB%E5%8A%A1%EF%BC%8C%E6%98%AF%E5%90%A6%E8%BF%98%E8%83%BD%E6%8B%BF%E5%88%B0%E7%BB%93%E6%9E%9C%EF%BC%9F"><span class="toc-text">已经被cancel的任务，是否还能拿到结果？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Future%E7%9A%84%E7%BC%BA%E9%99%B7%E4%BB%A5%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="toc-text">Future的缺陷以及解决方案</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#CompletionService"><span class="toc-text">CompletionService</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B-2"><span class="toc-text">简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%98%BB%E5%A1%9E%E5%92%8C%E9%9D%9E%E9%98%BB%E5%A1%9E%E8%8E%B7%E5%8F%96"><span class="toc-text">阻塞和非阻塞获取</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BB%A3%E7%A0%81%E8%A7%A3%E5%86%B3Future%E7%BC%BA%E9%99%B7"><span class="toc-text">代码解决Future缺陷</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8C%89%E5%AE%8C%E6%88%90%E9%A1%BA%E5%BA%8F%E8%8E%B7%E5%8F%96%E7%BB%93%E6%9E%9C%E9%AA%8C%E8%AF%81"><span class="toc-text">按完成顺序获取结果验证</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#CompleableFuture%EF%BC%88%E9%87%8D%E8%A6%81%EF%BC%8C%E5%BE%88%E5%B8%B8%E7%94%A8%EF%BC%89"><span class="toc-text">CompleableFuture（重要，很常用）</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E5%87%BA%E7%8E%B0CompletableFuture%EF%BC%9F"><span class="toc-text">为什么会出现CompletableFuture？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%AE%80%E4%BB%8B%E5%8F%8A%E6%B3%A8%E6%84%8F%E7%82%B9"><span class="toc-text">简介及注意点</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9E%84%E9%80%A0CompleableFuture"><span class="toc-text">构造CompleableFuture</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#runAsync"><span class="toc-text">runAsync</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#supplyAsync"><span class="toc-text">supplyAsync</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#anyOf"><span class="toc-text">anyOf</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#allOf"><span class="toc-text">allOf</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BB%84%E5%90%88%E6%96%B9%E6%B3%95"><span class="toc-text">组合方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E5%90%88%E4%B8%A4%E4%B8%AA%E4%BB%BB%E5%8A%A1%EF%BC%8C%E5%90%8C%E6%97%B6%E5%A4%84%E7%90%86%E4%B8%A4%E4%B8%AA%E7%BB%93%E6%9E%9C"><span class="toc-text">组合两个任务，同时处理两个结果</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E5%90%88%E4%B8%A4%E4%B8%AA%E4%BB%BB%E5%8A%A1%EF%BC%8C%E4%BB%BB%E5%8A%A1%E5%AE%8C%E6%88%90%E5%90%8E%E5%81%9A%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="toc-text">组合两个任务，任务完成后做的操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BD%93%E4%B8%A4%E4%B8%AA%E4%BB%BB%E5%8A%A1%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%AA%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%8C%E6%89%A7%E8%A1%8C%E4%B8%80%E4%B8%AA%E6%93%8D%E4%BD%9C"><span class="toc-text">当两个任务任意一个执行完成后，执行一个操作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BB%84%E5%90%88%E4%B8%A4%E4%B8%AA%E4%BB%BB%E5%8A%A1%EF%BC%8C%E5%A4%84%E7%90%86%E5%90%8E%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E7%BB%93%E6%9E%9C"><span class="toc-text">组合两个任务，处理后，返回一个结果</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%AC%AC%E4%B8%80%E4%B8%AA%E4%BB%BB%E5%8A%A1%E7%9A%84%E8%BE%93%E5%87%BA%E6%98%AF%E7%AC%AC%E4%BA%8C%E4%B8%AA%E4%BB%BB%E5%8A%A1%E7%9A%84%E8%BE%93%E5%85%A5"><span class="toc-text">第一个任务的输出是第二个任务的输入</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%AD%E8%BD%AC%E6%96%B9%E6%B3%95"><span class="toc-text">中转方法</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC"><span class="toc-text">有返回值</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%BD%93%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%E6%97%B6%E6%89%A7%E8%A1%8C%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="toc-text">当执行完成时执行的操作</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%BA%A7%E8%81%94%E6%93%8D%E4%BD%9C"><span class="toc-text">级联操作</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%A4%84%E7%90%86%E7%BB%93%E6%9E%9C%E7%9A%84%E6%93%8D%E4%BD%9C"><span class="toc-text">处理结果的操作</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC"><span class="toc-text">无返回值</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%A4%84%E7%90%86%E7%BB%93%E6%9E%9C"><span class="toc-text">处理结果</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%89%A7%E8%A1%8C%E5%AE%8C%E5%85%A8%E9%83%A8%E4%BB%BB%E5%8A%A1"><span class="toc-text">执行完全部任务</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BB%88%E7%BB%93%E6%96%B9%E6%B3%95"><span class="toc-text">终结方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%A4%84%E7%90%86%E5%BC%82%E5%B8%B8"><span class="toc-text">处理异常</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%AB%8B%E9%A9%AC%E8%8E%B7%E5%8F%96%E7%BB%93%E6%9E%9C"><span class="toc-text">立马获取结果</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A4%E6%96%AD%E7%BB%93%E6%9E%9C%E6%98%AF%E5%90%A6%E5%AE%8C%E6%88%90%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%AA%E5%AE%8C%E6%88%90%E5%88%99%E8%B5%8B%E4%BA%88%E7%BB%93%E6%9E%9C"><span class="toc-text">判断结果是否完成，如果未完成则赋予结果</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%A4%E6%96%AD%E7%BB%93%E6%9E%9C%E6%98%AF%E5%90%A6%E5%AE%8C%E6%88%90%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%AA%E5%AE%8C%E6%88%90%E8%BF%94%E5%9B%9E%E5%BC%82%E5%B8%B8"><span class="toc-text">判断结果是否完成，如果未完成返回异常</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%90%8E%E7%BB%AD%E8%8E%B7%E5%8F%96%E7%BB%93%E6%9E%9C%E4%BC%9A%E4%BA%A7%E7%94%9F%E5%BC%82%E5%B8%B8"><span class="toc-text">后续获取结果会产生异常</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-text">总结</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%8F%82%E8%80%83%EF%BC%9A"><span class="toc-text">参考：</span></a></li></ol></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By youthlql</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a href="https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral" target="_blank" rel="noopener" class="one-pan-link-mark"><img style="position:relative;top:-3px; " src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/upyun/logo.png" align="absmiddle" width="60px" height="30px"></a><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn"><img class="icp-icon" src= "" data-lazy-src="https://npm.elemecdn.com/lql_static@latest/logo/icp.png"><span>鄂ICP备19028890号</span></a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">简</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">本地搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://npm.elemecdn.com/@fancyapps/ui/dist/fancybox.umd.js"></script><script src="https://npm.elemecdn.com/instant.page/instantpage.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script defer src="https://npm.elemecdn.com/jquery@latest/dist/jquery.min.js"></script></div></body></html>